using System; using UnityEngine; using System.Collections.Generic; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Oxide.Core.Plugins; using System.Linq; namespace Oxide.Plugins { [Info("RadTownLoot", "Krungh Crow", "2.0.0")] [Description("Return of Radanimals with animal settings")] #region Changelogs and ToDo < 2.0.0 /********************************************************************** * * v1.1.2 : Changed spawnchance from 0-1 to 0-100 (to make it more clear) * v1.1.3 : Added check if initiator is player or npc * v1.1.3 : Added additional checks * v1.1.4 : Added nullchecks (OnEntityDeath) * v1.1.5 : Fix for wolf NRE * v1.1.6 : Better Null check * **********************************************************************/ #endregion #region Changelogs and ToDo > 2.0.0 /********************************************************************** * * 2.0.0 : Rewrite * : Optimised Hook Calls * : Backpacks show animal type * : Changed permissions * : Added support for Alpha and Omega animal types * : Extended internal Debug System * **********************************************************************/ #endregion class RadTownLoot : RustPlugin { [PluginReference]//example Plugin Clans, Friends; #region Variables string Chat_Perm = "radtownloot.chat"; string Command_Perm = "radtownloot.command"; string Loot_Perm = "radtownloot.loot"; ulong chaticon = 0; string prefix; bool Debug = false; bool IgnoreAlpha; bool IgnoreOmega; int HealthMin; int HealthMax; int RandomHealth; int DamageMin; int DamageMax; int RandomDamage; float Speed; bool ShowConsole = false; bool ChangeValues; #endregion #region Configuration void Init() { if (!LoadConfigVariables()) { Puts($"Config file ({this.Name}.json) issue detected. Please check syntax and fix."); return; } permission.RegisterPermission(Chat_Perm, this); permission.RegisterPermission(Command_Perm, this); permission.RegisterPermission(Loot_Perm, this); Debug = configData.PlugCFG.Debug; IgnoreAlpha = configData.Animals.IgnoreAlpha; IgnoreOmega = configData.Animals.IgnoreOmega; prefix = configData.PlugCFG.Prefix; chaticon = configData.PlugCFG.Chaticon; if (Debug) Puts($"[Debug] Debug for [{this.Name}] is active if unintentional change cfg and reload"); } private ConfigData configData; class ConfigData { [JsonProperty(PropertyName = "Main config")] public SettingsPlugin PlugCFG = new SettingsPlugin(); [JsonProperty(PropertyName = "Animal config")] public SettingsAnimals Animals = new SettingsAnimals(); } class SettingsPlugin { [JsonProperty(PropertyName = "Debug")] public bool Debug = false; [JsonProperty(PropertyName = "Chat Steam64ID")] public ulong Chaticon = 0; [JsonProperty(PropertyName = "Chat Prefix")] public string Prefix = "[RadTownLoot] : "; [JsonProperty(PropertyName = "Use Random Skins")] public bool RandomSkins = false; } class SettingsAnimals { [JsonProperty(PropertyName = "Skip Alpha Animals")] public bool IgnoreAlpha = true; [JsonProperty(PropertyName = "Skip Omega Animals")] public bool IgnoreOmega = true; [JsonProperty(PropertyName = "Bear settings")] public Spawns BearSpawns = new Spawns(); [JsonProperty(PropertyName = "Polarbear settings")] public Spawns PBearSpawns = new Spawns(); [JsonProperty(PropertyName = "Wolf settings")] public Spawns WolfSpawns = new Spawns(); } class Spawns { [JsonProperty(PropertyName = "Change stats on spawns")] public bool Change = false; [JsonProperty(PropertyName = "Show spawns in Console")] public bool ShowConsole = false; [JsonProperty(PropertyName = "Droprate 0-100")] public float ChanceOfCrate = 10.0f; [JsonProperty(PropertyName = "Minimum Health")] public int Healthmin = 150; [JsonProperty(PropertyName = "Maximum Health")] public int Healthmax = 250; [JsonProperty(PropertyName = "Minimum Strength (Att dmg)")] public int Damage = 20; [JsonProperty(PropertyName = "Maximum Strength (Att dmg")] public int DamageMax = 25; [JsonProperty(PropertyName = "Running Speed")] public float Speed = 6f; [JsonProperty(PropertyName = "Loot settings")] public LootSettings Loots = new LootSettings(); } class LootSettings { [JsonProperty(PropertyName = "Spawn Min Amount Items")] public int MinAmount = 1; [JsonProperty(PropertyName = "Spawn Max Amount Items")] public int MaxAmount = 3; [JsonProperty(PropertyName = "Loot Table", ObjectCreationHandling = ObjectCreationHandling.Replace)] public List Loot { get; set; } = DefaultLoot; } 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 { ["Info"] = "Some bears and wolves can spawn backpacks like in Legacy Rust.\n\n", ["InvalidInput"] = "Please enter a valid command!", ["NoPermission"] = "You do not have permission to use that command!", ["RadTownLoot"] = "The {0} dropped something!", }, this); } #endregion #region Commands [ChatCommand("rad")] private void cmdRad(BasePlayer player, string command, string[] args) { if (!HasPerm(player, Chat_Perm)) { Player.Message(player, msg("NoPermission", player.UserIDString), chaticon); if (Debug) Puts($"[Debug] {player} had no permission for using Commands"); return; } if (args.Length == 0) Player.Message(player, msg("InvalidInput", player.UserIDString), chaticon); else { if (args[0].ToLower() == "animals") { Player.Message(player, string.Format(msg("Info", player.UserIDString)) //Bear Info + info("Bear : Pop ") + Bear.Population.ToString() + info(" ") + info("Health ") + configData.Animals.BearSpawns.Healthmin.ToString() + info("/") + configData.Animals.BearSpawns.Healthmax.ToString() + info("") + info($" Alive {AnimalCount("Bear")} ") //Polarbear info + info("\nPolarbear : Pop ") + Polarbear.Population.ToString() + info(" ") + info($"Health {configData.Animals.PBearSpawns.Healthmin.ToString()}/{configData.Animals.PBearSpawns.Healthmax.ToString()}") + info($" Alive {AnimalCount("Polarbear")} ") //Wolf Info + info("\nWolf : Pop ") + Wolf.Population.ToString() + info(" ") + info($"Health {configData.Animals.WolfSpawns.Healthmin.ToString()}/{configData.Animals.WolfSpawns.Healthmax.ToString()}") + info($" Alive {AnimalCount("Wolf")} ") , chaticon); return; } Player.Message(player, msg("InvalidInput", player.UserIDString), chaticon); } } #endregion #region Message helpers private string msg(string key, string id = null) => prefix + lang.GetMessage(key, this, id); private string info(string key, string id = null) => lang.GetMessage(key, this, id); void TIP(BasePlayer player, string message, float dur) { if (player == null) return; string msg = info(message);//takes the message from languagefile player.SendConsoleCommand("gametip.showgametip", msg); timer.Once(dur, () => player?.SendConsoleCommand("gametip.hidegametip")); } #endregion #region Oxide Hooks void OnEntityDeath(BaseAnimalNPC animal, HitInfo info) { if (animal == null || info == null) return; if ((animal.name.Contains("Alpha") && IgnoreAlpha) || (animal.name.Contains("Omega") && IgnoreOmega)) { if (Debug) Puts($"Skipping triggers for {animal.name}"); return; } BasePlayer attacker = info.InitiatorPlayer; if (attacker == null) return; var wolfrate = configData.Animals.WolfSpawns.ChanceOfCrate; var bearrate = configData.Animals.BearSpawns.ChanceOfCrate; var pbearrate = configData.Animals.PBearSpawns.ChanceOfCrate; if (animal is Wolf && (HasPerm(attacker, Loot_Perm))) { if (wolfrate <= 0f || UnityEngine.Random.value > wolfrate / 100) { if (Debug) Puts("wolfrate was not the random value skipping loot"); return; } SpawnRadLoot(animal.transform.position + new Vector3(0f, 0.5f, 0f), animal.transform.rotation, "Wolf"); { if (HasPerm(attacker, Chat_Perm)) Player.Message(attacker, string.Format(msg("RadTownLoot", attacker.UserIDString), animal.name), chaticon); LogToFile("RadTownKills", $"{DateTime.Now:h:mm:ss tt}] {attacker} killed a {animal.name} and loot was dropped", this); } } if (animal is Bear && (HasPerm(attacker, Loot_Perm))) { if (bearrate <= 0f || UnityEngine.Random.value > bearrate / 100) { if (Debug) Puts("bearrate was not the random value skipping loot"); return; } SpawnRadLoot(animal.transform.position + new Vector3(0f, 0.5f, 0f), animal.transform.rotation, "Bear"); { if (HasPerm(attacker, Chat_Perm)) Player.Message(attacker, string.Format(msg("RadTownLoot", attacker.UserIDString), animal.name), chaticon); LogToFile("RadTownKills", $"{DateTime.Now:h:mm:ss tt}] {attacker} killed a {animal.name} and loot was dropped", this); } } if (animal is Polarbear && (HasPerm(attacker, Loot_Perm))) { if (bearrate <= 0f || UnityEngine.Random.value > pbearrate / 100) { if (Debug) Puts("polarbearrate was not the random value skipping loot"); return; } SpawnRadLoot(animal.transform.position + new Vector3(0f, 0.5f, 0f), animal.transform.rotation, "Polarbear"); { if (HasPerm(attacker, Chat_Perm)) Player.Message(attacker, string.Format(msg("RadTownLoot", attacker.UserIDString), animal.name), chaticon); LogToFile("RadTownKills", $"{DateTime.Now:h:mm:ss tt}] {attacker} killed a {animal.name} and loot was dropped", this); } } return; } void OnEntitySpawned(BaseAnimalNPC animal) { if (animal == null) return; ShowConsole = false; ChangeValues = false; if ((animal.name.Contains("Alpha") && IgnoreAlpha) || (animal.name.Contains("Omega") && IgnoreOmega)) { if (Debug) Puts($"Skipping spawn values for {animal.name}"); return; } if (animal is Bear) { HealthMin = configData.Animals.BearSpawns.Healthmin; HealthMax = configData.Animals.BearSpawns.Healthmax; DamageMin = configData.Animals.BearSpawns.Damage; DamageMax = configData.Animals.BearSpawns.DamageMax; Speed = configData.Animals.BearSpawns.Speed; ShowConsole = configData.Animals.BearSpawns.ShowConsole; ChangeValues = configData.Animals.BearSpawns.Change; } if (animal is Polarbear) { HealthMin = configData.Animals.PBearSpawns.Healthmin; HealthMax = configData.Animals.PBearSpawns.Healthmax; DamageMin = configData.Animals.PBearSpawns.Damage; DamageMax = configData.Animals.PBearSpawns.DamageMax; Speed = configData.Animals.PBearSpawns.Speed; ShowConsole = configData.Animals.PBearSpawns.ShowConsole; ChangeValues = configData.Animals.PBearSpawns.Change; } if (animal is Wolf) { HealthMin = configData.Animals.WolfSpawns.Healthmin; HealthMax = configData.Animals.WolfSpawns.Healthmax; DamageMin = configData.Animals.WolfSpawns.Damage; DamageMax = configData.Animals.WolfSpawns.DamageMax; Speed = configData.Animals.WolfSpawns.Speed; ShowConsole = configData.Animals.WolfSpawns.ShowConsole; ChangeValues = configData.Animals.WolfSpawns.Change; } if (!ChangeValues) return; RandomHealth = UnityEngine.Random.Range(HealthMin,HealthMax); RandomDamage = UnityEngine.Random.Range(DamageMin, DamageMax); animal.InitializeHealth(RandomHealth, RandomHealth); animal.AttackDamage = RandomDamage; animal.Stats.Speed = Speed; animal.Stats.TurnSpeed = Speed; if (ShowConsole) Puts($"A {animal.name} spawned with {RandomHealth} HP and {RandomDamage} Strength"); } #endregion #region Helpers object AnimalCount(string _animal) { if (_animal == "Wolf") return BaseNetworkable.serverEntities.OfType().Count().ToString(); if (_animal == "Bear") return BaseNetworkable.serverEntities.OfType().Count().ToString(); if (_animal == "Polarbear") return BaseNetworkable.serverEntities.OfType().Count().ToString(); else return "N/a"; } bool HasPerm(BasePlayer player, string perm) { return (permission.UserHasPermission(player.UserIDString, perm));} #endregion #region Loot private Dictionary> Skins { get; set; } = new Dictionary>(); private static List DefaultLoot { get { return new List { new LootItems { shortname = "ammo.pistol", amount = 5, skin = 0, amountMin = 5 }, new LootItems { shortname = "ammo.pistol.fire", amount = 5, skin = 0, amountMin = 5 }, new LootItems { shortname = "ammo.pistol.hv", amount = 5, skin = 0, amountMin = 5 }, }; } } public class LootItems { public string shortname { get; set; } public int amount { get; set; } public ulong skin { get; set; } public int amountMin { get; set; } } private void SpawnRadLoot(Vector3 pos, Quaternion rot, string AnimalType) { var backpack = GameManager.server.CreateEntity(StringPool.Get(1519640547), pos, rot, true) as DroppedItemContainer; if (backpack == null) return; backpack.inventory = new ItemContainer(); backpack.inventory.ServerInitialize(null, 36); backpack.inventory.GiveUID(); backpack.inventory.entityOwner = backpack; backpack.inventory.SetFlag(ItemContainer.Flag.NoItemInput, true); backpack.playerName = "Rad " + AnimalType; backpack.Spawn(); if (AnimalType == "Wolf") { if(Debug) Puts($"AnimalType is {AnimalType}"); SpawnLoot(backpack.inventory, configData.Animals.WolfSpawns.Loots.Loot.ToList(), AnimalType); } if (AnimalType == "Bear") { if (Debug) Puts($"AnimalType is {AnimalType}"); SpawnLoot(backpack.inventory, configData.Animals.BearSpawns.Loots.Loot.ToList(), AnimalType); } if (AnimalType == "Polarbear") { if (Debug) Puts($"AnimalType is {AnimalType}"); SpawnLoot(backpack.inventory, configData.Animals.PBearSpawns.Loots.Loot.ToList(), AnimalType); } } private void SpawnLoot(ItemContainer container, List loot, string AnimalType) { int total = 0; if (AnimalType == "Wolf") total = UnityEngine.Random.Range(Math.Min(loot.Count, configData.Animals.WolfSpawns.Loots.MinAmount), Math.Min(loot.Count, configData.Animals.WolfSpawns.Loots.MaxAmount)); if (AnimalType == "Bear") total = UnityEngine.Random.Range(Math.Min(loot.Count, configData.Animals.BearSpawns.Loots.MinAmount), Math.Min(loot.Count, configData.Animals.BearSpawns.Loots.MaxAmount)); if (AnimalType == "Polarbear") total = UnityEngine.Random.Range(Math.Min(loot.Count, configData.Animals.PBearSpawns.Loots.MinAmount), Math.Min(loot.Count, configData.Animals.PBearSpawns.Loots.MaxAmount)); if (Debug) Puts($"{AnimalType} {total} items"); if (total == 0 || loot.Count == 0) return; container.capacity = total; ItemDefinition def; List skins; LootItems lootItem; for (int j = 0; j < total; j++) { if (loot.Count == 0) break; lootItem = loot.GetRandom(); loot.Remove(lootItem); if (lootItem.amount <= 0) continue; string shortname = lootItem.shortname; bool isBlueprint = shortname.EndsWith(".bp"); if (isBlueprint) shortname = shortname.Replace(".bp", string.Empty); def = ItemManager.FindItemDefinition(shortname); if (def == null) { Puts("Invalid shortname: {0}", lootItem.shortname); continue; } ulong skin = lootItem.skin; if (configData.PlugCFG.RandomSkins && skin == 0 || configData.PlugCFG.RandomSkins && skin == 0) { skins = GetItemSkins(def); if (skins.Count > 0) skin = skins.GetRandom(); } int amount = lootItem.amount; if (amount <= 0) continue; if (lootItem.amountMin > 0 && lootItem.amountMin < lootItem.amount) { amount = UnityEngine.Random.Range(lootItem.amountMin, lootItem.amount); } Item item; if (isBlueprint) { item = ItemManager.CreateByItemID(-996920608, 1, 0); if (item == null) continue; item.blueprintTarget = def.itemid; item.amount = amount; } else item = ItemManager.Create(def, amount, skin); if (!item.MoveToContainer(container, -1, false)) item.Remove(); } } private List GetItemSkins(ItemDefinition def) { List skins; if (!Skins.TryGetValue(def.shortname, out skins)) { Skins[def.shortname] = skins = ExtractItemSkins(def, skins); } return skins; } private List ExtractItemSkins(ItemDefinition def, List skins) { skins = new List(); foreach (var skin in def.skins) { skins.Add(Convert.ToUInt64(skin.id)); } foreach (var asi in Rust.Workshop.Approved.All.Values) { if (!string.IsNullOrEmpty(asi.Skinnable.ItemName) && asi.Skinnable.ItemName == def.shortname) { skins.Add(Convert.ToUInt64(asi.WorkshopdId)); } } return skins; } #endregion } }