C#:
using System;
using System.Collections.Generic;
using UnityEngine;
using Oxide.Core.Plugins;
using Newtonsoft.Json;
using Oxide.Core;
using Rust.Ai.Gen2;
namespace Oxide.Plugins
{
[Info("Back To The Wild" , "Krungh Crow" , "2.2.7")]
[Description("Animal Randomised health, damage and info")]
public class BackToTheWild : RustPlugin
{
[PluginReference] private Plugin ChickenBow, BeastMaster;
private Dictionary<string , AnimalSettings> animalSettingsMap;
private bool Debug;
private const string Admin_Perm = "backtothewild.admin";
private const string Prefix = "[BackToTheWild] : ";
private const ulong Chaticon = 0;
private void Init()
{
LoadConfig();
permission.RegisterPermission(Admin_Perm , this);
}
protected override void LoadDefaultConfig()
{
Puts("Creating default configuration file...");
var defaultSettings = GetDefaultAnimalSettings();
Config.WriteObject(new ConfigData { AnimalSettings = defaultSettings , Debug = true } , true);
}
private void LoadConfig()
{
try
{
var config = Config.ReadObject<ConfigData>();
animalSettingsMap = config.AnimalSettings ?? GetDefaultAnimalSettings();
Debug = config.Debug;
Puts("Loaded configuration successfully.");
}
catch (Exception ex)
{
Puts("Config file issue detected. Please delete file, or check syntax and fix.");
Puts(ex.ToString());
return;
}
}
protected override void LoadDefaultMessages()
{
lang.RegisterMessages(new Dictionary<string , string>
{
["InvalidInput"] = "<color=red>Please enter a valid command!</color>" ,
["Info"] = "Animal related info :\n\n" ,
["NoPermission"] = "<color=red>You do not have permission to use that command!</color>" ,
["AnimalsInfo"] = "Animals with stats changing on spawn: {animals}" ,
["NoAnimals"] = "No animals with stats changes on spawn."
} , this);
}
private Dictionary<string , AnimalSettings> GetDefaultAnimalSettings()
{
var settingsMap = new Dictionary<string , AnimalSettings>();
foreach (var animalPrefab in GetDynamicAnimalTypes())
{
settingsMap[animalPrefab] = new AnimalSettings
{
ChangeStatsOnSpawn = true ,
MinimumHealth = 100 ,
MaximumHealth = 500 ,
MinimumStrength = 10 ,
MaximumStrength = 30 ,
RunningSpeed = 1.0f ,
Alpha = new AlphaSettings
{
CanSpawnAsAlpha = true ,
Spawnrate = 10 ,
HealthMultiplier = 2.0f ,
StrengthMultiplier = 1.5f ,
SpeedMultiplier = 1.0f
} ,
ChangePopulation = false ,
Population = 0
};
}
return settingsMap;
}
private IEnumerable<string> GetDynamicAnimalTypes()
{
var animalTypes = new HashSet<string>
{
"wolf2"
};
foreach (var net in BaseNetworkable.serverEntities)
{
if (net == null) continue;
if (net is BaseAnimalNPC animal)
{
var prefab = animal.ShortPrefabName.ToLower();
if (prefab.Contains("shark") || prefab.Contains("horse"))
continue;
animalTypes.Add(prefab);
continue;
}
if (net is BaseNPC2 npc2)
{
if (npc2.Categorize() == "Scientist2")
continue;
var prefab = npc2.ShortPrefabName.ToLower();
animalTypes.Add(prefab);
}
}
return animalTypes;
}
private void CheckAndAddNewAnimals()
{
var currentAnimalTypes = GetDynamicAnimalTypes();
bool newAnimalsAdded = false;
foreach (var animalType in currentAnimalTypes)
{
if (!animalSettingsMap.ContainsKey(animalType))
{
animalSettingsMap[animalType] = new AnimalSettings
{
ChangeStatsOnSpawn = true ,
MinimumHealth = 100 ,
MaximumHealth = 500 ,
MinimumStrength = 10 ,
MaximumStrength = 30 ,
RunningSpeed = 1.0f ,
Alpha = new AlphaSettings
{
CanSpawnAsAlpha = true ,
Spawnrate = 10 ,
HealthMultiplier = 2.0f ,
StrengthMultiplier = 1.5f ,
SpeedMultiplier = 1.0f
} ,
ChangePopulation = false ,
Population = 0
};
newAnimalsAdded = true;
Debugmsg($"Added new animal '{animalType}' with default settings.");
}
}
if (newAnimalsAdded)
{
Config.WriteObject(new ConfigData { AnimalSettings = animalSettingsMap , Debug = Debug } , true);
Puts("Configuration updated with new animals.");
}
else
{
Puts("No new animals found, configuration remains unchanged.");
}
}
private class ConfigData
{
[JsonProperty("Debug")]
public bool Debug { get; set; }
public Dictionary<string , AnimalSettings> AnimalSettings { get; set; }
}
private class AnimalSettings
{
[JsonProperty("Change stats on spawns")]
public bool ChangeStatsOnSpawn { get; set; }
[JsonProperty("Minimum Health")]
public float MinimumHealth { get; set; }
[JsonProperty("Maximum Health")]
public float MaximumHealth { get; set; }
[JsonProperty("Minimum Strength (Att dmg)")]
public float MinimumStrength { get; set; }
[JsonProperty("Maximum Strength (Att dmg)")]
public float MaximumStrength { get; set; }
[JsonProperty("Running Speed")]
public float RunningSpeed { get; set; }
public AlphaSettings Alpha { get; set; }
[JsonProperty("Change Population")]
public bool ChangePopulation { get; set; }
[JsonProperty("Population")]
public int Population { get; set; }
}
private class AlphaSettings
{
[JsonProperty("Can spawn as alpha")]
public bool CanSpawnAsAlpha { get; set; }
[JsonProperty("Spawnrate (0-100)")]
public int Spawnrate { get; set; }
[JsonProperty("Health Multiplier")]
public float HealthMultiplier { get; set; }
[JsonProperty("Strength Multiplier (Att dmg)")]
public float StrengthMultiplier { get; set; }
[JsonProperty("Speed Multiplier")]
public float SpeedMultiplier { get; set; }
}
private void Debugmsg(string key)
{
if (Debug) Puts($"[Debug] {key}");
}
private void OnEntitySpawned(BaseAnimalNPC animal)
{
if (animal == null || !animal.IsValid())
{
Debugmsg("Spawned BaseAnimalNPC is null or no longer valid.");
return;
}
if (BeastMaster != null)
{
object beastMasterResult = Interface.CallHook("IsBeastMasterAnimal" , animal);
if (beastMasterResult is bool && (bool)beastMasterResult)
{
Debugmsg($"Skipping BeastMaster BaseAnimalNPC: {animal.ShortPrefabName}");
return;
}
}
string animalName = animal.ShortPrefabName.ToLower();
if (animalName.Contains("chicken"))
{
if (ChickenBow == null)
{
Debugmsg("ChickenBow plugin is null! Cannot check for ChickenBow chickens.");
}
else if (animal.net != null && animal.net.ID.IsValid)
{
try
{
object chickenBowResult = ChickenBow.Call("IsSpawnedChicken" , animal.net.ID);
if (chickenBowResult is bool isChickenSpawned && isChickenSpawned)
{
Debugmsg($"ChickenBow chicken detected: {animalName}");
return;
}
}
catch (Exception ex)
{
Debugmsg($"Error checking ChickenBow for BaseAnimalNPC: {ex.Message}");
}
}
}
UpdateAnimalStats(animal);
}
private void OnEntitySpawned(BaseNPC2 npc)
{
if (npc == null || !npc.IsValid())
{
Debugmsg("Spawned BaseNPC2 is null or no longer valid.");
return;
}
if (npc.Categorize() == "Scientist2")
{
Debugmsg($"Skipping Scientist2 NPC: {npc.ShortPrefabName}");
return;
}
if (BeastMaster != null)
{
object beastMasterResult = Interface.CallHook("IsBeastMasterAnimal" , npc);
if (beastMasterResult is bool && (bool)beastMasterResult)
{
Debugmsg($"Skipping BeastMaster BaseNPC2: {npc.ShortPrefabName}");
return;
}
}
string npcName = npc.ShortPrefabName.ToLower();
if (npcName.Contains("chicken"))
{
if (ChickenBow == null)
{
Debugmsg("ChickenBow plugin is null! Cannot check for ChickenBow chickens.");
}
else if (npc.net != null && npc.net.ID.IsValid)
{
try
{
object chickenBowResult = ChickenBow.Call("IsSpawnedChicken" , npc.net.ID);
if (chickenBowResult is bool isChickenSpawned && isChickenSpawned)
{
Debugmsg($"ChickenBow chicken detected: {npcName}");
return;
}
}
catch (Exception ex)
{
Debugmsg($"Error checking ChickenBow for BaseNPC2: {ex.Message}");
}
}
}
UpdateAnimalStats(npc);
}
private void UpdateAnimalStats(BaseEntity animalEntity)
{
if (animalEntity == null) return;
string animalName = animalEntity.ShortPrefabName.ToLower();
AnimalSettings settings;
if (!animalSettingsMap.TryGetValue(animalName , out settings))
{
Debugmsg($"No configuration found for animal: {animalName}");
return;
}
if (!settings.ChangeStatsOnSpawn)
return;
float minHealth = settings.MinimumHealth;
float maxHealth = settings.MaximumHealth;
float minDamage = settings.MinimumStrength;
float maxDamage = settings.MaximumStrength;
float speed = settings.RunningSpeed;
if (settings.Alpha.CanSpawnAsAlpha && SpawnRate(settings.Alpha.Spawnrate))
{
float alphaHealthMultiplier = settings.Alpha.HealthMultiplier;
float alphaDamageMultiplier = settings.Alpha.StrengthMultiplier;
float alphaSpeedMultiplier = settings.Alpha.SpeedMultiplier;
animalEntity.name = $"Alpha {animalName}";
minHealth *= alphaHealthMultiplier;
maxHealth *= alphaHealthMultiplier;
minDamage *= alphaDamageMultiplier;
maxDamage *= alphaDamageMultiplier;
speed *= alphaSpeedMultiplier;
float randomAlphaHealth = UnityEngine.Random.Range(minHealth , maxHealth);
float randomAlphaDamage = UnityEngine.Random.Range(minDamage , maxDamage);
if (animalEntity is BaseAnimalNPC baseAnimal && baseAnimal.IsValid())
{
baseAnimal.InitializeHealth(randomAlphaHealth , randomAlphaHealth);
baseAnimal.AttackDamage = randomAlphaDamage;
baseAnimal.Stats.Speed = speed;
baseAnimal.Stats.TurnSpeed = speed;
baseAnimal.NewAI = true;
}
else if (animalEntity is BaseNPC2 baseNpc && baseNpc.IsValid())
{
baseNpc.InitializeHealth(randomAlphaHealth , randomAlphaHealth);
}
Puts($"{animalEntity.name} spawned as an Alpha with health {randomAlphaHealth}, damage ({randomAlphaDamage}), and speed {speed}");
return;
}
animalEntity.name = animalName;
float randomHealth = UnityEngine.Random.Range(minHealth , maxHealth);
float randomDamage = UnityEngine.Random.Range(minDamage , maxDamage);
if (animalEntity is BaseAnimalNPC normalAnimal)
{
normalAnimal.InitializeHealth(randomHealth , randomHealth);
normalAnimal.lifestate = BaseCombatEntity.LifeState.Alive;
normalAnimal.AttackDamage = randomDamage;
normalAnimal.Stats.Speed = speed;
normalAnimal.Stats.TurnSpeed = speed;
normalAnimal.NewAI = true;
}
else if (animalEntity is BaseNPC2 normalNpc)
{
normalNpc.InitializeHealth(randomHealth , randomHealth);
}
Debugmsg($"Updated {animalName} stats: Health ({randomHealth}), Damage ({randomDamage}), Speed ({speed})");
}
private bool SpawnRate(int spawnRate)
{
return UnityEngine.Random.Range(0 , 100) < spawnRate;
}
private void OnServerInitialized()
{
CheckAndAddNewAnimals();
if (animalSettingsMap == null)
return;
Debugmsg("Changing server population settings based on configuration...");
var animalCounts = new Dictionary<string , int>();
foreach (var kvp in animalSettingsMap)
{
var animalType = kvp.Key.ToLower();
var settings = kvp.Value;
if (settings.ChangePopulation)
{
int populationValue = settings.Population;
string command = $"{animalType}.population";
Server.Command(command , populationValue);
Debugmsg($"Set population for {animalType} to {populationValue}");
}
else
{
Debugmsg($"Population change not enabled for {animalType}");
}
animalCounts[animalType] = 0;
}
foreach (var net in BaseNetworkable.serverEntities)
{
if (net == null) continue;
if (net is BaseAnimalNPC animal)
{
var animalName = animal.ShortPrefabName.ToLower();
AnimalSettings settings;
if (animalSettingsMap.TryGetValue(animalName , out settings) && settings.ChangeStatsOnSpawn)
{
UpdateAnimalStats(animal);
int count;
if (animalCounts.TryGetValue(animalName , out count))
animalCounts[animalName] = count + 1;
else
animalCounts[animalName] = 1;
}
continue;
}
if (net is BaseNPC2 npc)
{
if (npc.Categorize() == "Scientist2")
continue;
var npcName = npc.ShortPrefabName.ToLower();
AnimalSettings settings;
if (animalSettingsMap.TryGetValue(npcName , out settings) && settings.ChangeStatsOnSpawn)
{
UpdateAnimalStats(npc);
int count;
if (animalCounts.TryGetValue(npcName , out count))
animalCounts[npcName] = count + 1;
else
animalCounts[npcName] = 1;
}
}
}
foreach (var kvp in animalCounts)
{
if (kvp.Value <= 0)
continue;
string animalType = kvp.Key;
string formattedMessage;
if (animalType == "wolf")
formattedMessage = $"Total of {kvp.Value} wolves updated";
else
formattedMessage = $"Total of {kvp.Value} {animalType}s updated";
Puts(formattedMessage);
}
}
#region Commands
[ChatCommand("bttw")]
private void cmdbttw(BasePlayer player , string command , string[] args)
{
if (!HasPerm(player , Admin_Perm))
{
Player.Message(player , Prefix + msg("NoPermission" , player.UserIDString) , Chaticon);
return;
}
if (args.Length == 0)
{
Player.Message(player , Prefix + msg("InvalidInput" , player.UserIDString) , Chaticon);
return;
}
if (args[0].ToLower() == "animals")
{
string animalsInfo = GetAnimalsInfoMessage();
string message = msg("Info" , player.UserIDString) + "\n" + msg("AnimalsInfo").Replace("{animals}" , animalsInfo);
Player.Message(player , Prefix + message , Chaticon);
return;
}
Player.Message(player , Prefix + msg("InvalidInput" , player.UserIDString) , Chaticon);
}
private string GetAnimalsInfoMessage()
{
string message = string.Empty;
foreach (var kvp in animalSettingsMap)
{
var animalName = kvp.Key;
var settings = kvp.Value;
if (settings.ChangeStatsOnSpawn)
message += $"{animalName}, ";
}
if (message.EndsWith(", "))
message = message.Substring(0 , message.Length - 2);
if (string.IsNullOrEmpty(message))
message = msg("NoAnimals");
return message;
}
private bool HasPerm(BasePlayer player , string perm)
{
return permission.UserHasPermission(player.UserIDString , perm);
}
private string msg(string key , string id = null)
{
return lang.GetMessage(key , this , id);
}
#endregion
}
}