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
}
}