C#:
using System;
using System.Collections.Generic;
using System.Linq;
using Oxide.Core;
using Oxide.Core.Plugins;
using UnityEngine;
using Random = System.Random;
namespace Oxide.Plugins {
[Info("Mutation System", "0killrest", "1.0.0")]
[Description("Animals and players can mutate with unique abilities")]
internal class MutationSystem : RustPlugin {
#region Configuration
private static ConfigData config;
private class ConfigData {
public bool Enabled {
get;
set;
}
= true;
public float MutationCheckIntervalSeconds {
get;
set;
}
= 60f;
public float AnimalMutationChance {
get;
set;
}
= 0.05f;
public float PlayerMutationChanceInRadiation {
get;
set;
}
= 0.01f;
public int MutationDurationSeconds {
get;
set;
}
= 300;
public List<AnimalMutation> AnimalMutations {
get;
set;
}
public List<PlayerMutation> PlayerMutations {
get;
set;
}
public ConfigData() {
AnimalMutations = new List<AnimalMutation> {
new AnimalMutation {
Name = "Radioactive Bear", OriginalPrefab = "assets/rust.ai/agents/bear/bear.prefab", NewPrefab = "assets/rust.ai/agents/bear/bear.prefab", HealthMultiplier = 2.5f, DamageMultiplier = 2f, ScaleMultiplier = 1.5f, GlowColor = "#00ff00", ExplodesOnDeath = true, DropMultiplier = 3
}
, new AnimalMutation {
Name = "Frozen Wolf", OriginalPrefab = "assets/rust.ai/agents/wolf/wolf.prefab", NewPrefab = "assets/rust.ai/agents/wolf/wolf.prefab", HealthMultiplier = 1.8f, DamageMultiplier = 1.5f, ScaleMultiplier = 1.3f, GlowColor = "#00ccff", SpeedMultiplier = 1.5f, DropMultiplier = 2
}
, new AnimalMutation {
Name = "Lava Boar", OriginalPrefab = "assets/rust.ai/agents/boar/boar.prefab", NewPrefab = "assets/rust.ai/agents/boar/boar.prefab", HealthMultiplier = 2f, DamageMultiplier = 1.8f, ScaleMultiplier = 1.4f, GlowColor = "#ff5500", LeavesFireTrail = true, DropMultiplier = 2
}
, new AnimalMutation {
Name = "Toxic Stag", OriginalPrefab = "assets/rust.ai/agents/stag/stag.prefab", NewPrefab = "assets/rust.ai/agents/stag/stag.prefab", HealthMultiplier = 1.5f, DamageMultiplier = 1.3f, ScaleMultiplier = 1.2f, GlowColor = "#88ff00", DropMultiplier = 2
}
}
;
PlayerMutations = new List<PlayerMutation> {
new PlayerMutation {
Name = "Speed Demon", Color = "#00ff00", SpeedMultiplier = 1.5f, Description = "You move 50% faster!"
}
, new PlayerMutation {
Name = "Tank", Color = "#ff0000", HealthMultiplier = 2f, Description = "You have double health!"
}
, new PlayerMutation {
Name = "Berserker", Color = "#ff6600", DamageMultiplier = 1.5f, Description = "You deal 50% more damage!"
}
, new PlayerMutation {
Name = "Invisible", Color = "#888888", Invisible = true, Description = "You are partially invisible!"
}
, new PlayerMutation {
Name = "Radioactive", Color = "#00ff00", RadiationDamage = 5f, Description = "You radiate damage to nearby enemies!"
}
}
;
}
}
public class AnimalMutation {
public string Name {
get;
set;
}
public string OriginalPrefab {
get;
set;
}
public string NewPrefab {
get;
set;
}
public float HealthMultiplier {
get;
set;
}
= 1f;
public float DamageMultiplier {
get;
set;
}
= 1f;
public float ScaleMultiplier {
get;
set;
}
= 1f;
public float SpeedMultiplier {
get;
set;
}
= 1f;
public string GlowColor {
get;
set;
}
public bool ExplodesOnDeath {
get;
set;
}
public bool LeavesFireTrail {
get;
set;
}
public int DropMultiplier {
get;
set;
}
= 1;
}
public class PlayerMutation {
public string Name {
get;
set;
}
public string Color {
get;
set;
}
public float SpeedMultiplier {
get;
set;
}
= 1f;
public float HealthMultiplier {
get;
set;
}
= 1f;
public float DamageMultiplier {
get;
set;
}
= 1f;
public bool Invisible {
get;
set;
}
public float RadiationDamage {
get;
set;
}
public string Description {
get;
set;
}
}
protected override void LoadConfig() {
base.LoadConfig();
config = Config.ReadObject<ConfigData>();
if (config == null) {
LoadDefaultConfig();
}
}
protected override void LoadDefaultConfig() {
config = new ConfigData();
PrintWarning("Default configuration created.Edit it in oxide/config/MutationSystem.json");
SaveConfig();
}
protected override void SaveConfig() => Config.WriteObject(config);
#endregion
#region Data Storage
private Dictionary<ulong, ActiveMutation> activePlayerMutations = new Dictionary<ulong, ActiveMutation>();
private Dictionary<BaseEntity, AnimalMutation> activeAnimalMutations = new Dictionary<BaseEntity, AnimalMutation>();
private Random random = new Random();
private Timer checkTimer;
private class ActiveMutation {
public PlayerMutation Mutation {
get;
set;
}
public float EndTime {
get;
set;
}
public float OriginalMaxHealth {
get;
set;
}
public float OriginalSpeed {
get;
set;
}
}
#endregion
#region Hooks
private void Init() {
permission.RegisterPermission("mutationsystem.admin", this);
}
private void OnServerInitialized() {
if (config.Enabled) {
StartMutationCheck();
}
}
private void Unload() {
checkTimer?.Destroy();
}
private void StartMutationCheck() {
if (checkTimer != null) checkTimer.Destroy();
checkTimer = timer.Repeat(config.MutationCheckIntervalSeconds, 0, () => {
CheckForMutations();
}
);
}
private void CheckForMutations() {
// Check animals
foreach (var animal in BaseNetworkable.serverEntities.OfType<BaseNPC>()) {
if (animal == null || animal.IsDead()) continue;
if (activeAnimalMutations.ContainsKey(animal)) continue;
if (random.NextDouble() < config.AnimalMutationChance) {
MutateAnimal(animal);
}
}
// Check players in radiation
foreach (var player in BasePlayer.activePlayerList) {
if (player == null || player.IsDead()) continue;
if (activePlayerMutations.ContainsKey(player.userID)) continue;
if (player.metabolism.radiation_poison.value > 50) {
if (random.NextDouble() < config.PlayerMutationChanceInRadiation) {
MutatePlayer(player);
}
}
}
}
private void MutateAnimal(BaseNPC animal) {
var availableMutations = config.AnimalMutations.Where(m => m.OriginalPrefab == animal.ShortPrefabName).ToList();
if (availableMutations.Count == 0) return;
var mutation = availableMutations[random.Next(availableMutations.Count)];
// Apply mutation effects
float originalHealth = animal.health;
float originalMaxHealth = animal.MaxHealth();
animal.health = originalHealth * mutation.HealthMultiplier;
animal.InitializeHealth(originalMaxHealth * mutation.HealthMultiplier, originalMaxHealth * mutation.HealthMultiplier);
// Scale entity
animal.transform.localScale = Vector3.one * mutation.ScaleMultiplier;
// Speed multiplier
if (mutation.SpeedMultiplier != 1f) {
var agent = animal.GetComponent<UnityEngine.AI.NavMeshAgent>();
if (agent != null) {
agent.speed *= mutation.SpeedMultiplier;
}
}
// Glow effect
if (!string.IsNullOrEmpty(mutation.GlowColor)) {
AddGlowEffect(animal, mutation.GlowColor);
}
// Set custom name
animal.displayName = $"<color={mutation.GlowColor}>★ MUTATED {mutation.Name.ToUpper()} ★</color>";
activeAnimalMutations[animal] = mutation;
Puts($"Animal mutated: {mutation.Name} at {animal.transform.position}");
// Broadcast to nearby players
var nearbyPlayers = BasePlayer.activePlayerList.Where(p => Vector3.Distance(p.transform.position, animal.transform.position) < 100f);
foreach (var player in nearbyPlayers) {
SendReply(player, $"<color=red>⚠️ A mutated {mutation.Name} appears nearby!</color>");
}
}
private void MutatePlayer(BasePlayer player) {
var availableMutations = config.PlayerMutations;
if (availableMutations.Count == 0) return;
var mutation = availableMutations[random.Next(availableMutations.Count)];
var active = new ActiveMutation {
Mutation = mutation, EndTime = Time.realtimeSinceStartup + config.MutationDurationSeconds, OriginalMaxHealth = player.MaxHealth(), OriginalSpeed = 1f
}
;
// Apply effects
if (mutation.HealthMultiplier != 1f) {
player.InitializeHealth(player.MaxHealth() * mutation.HealthMultiplier, player.MaxHealth() * mutation.HealthMultiplier);
}
if (mutation.SpeedMultiplier != 1f) {
// Apply speed modifier via temporary permission or effect
player.SetPlayerFlag(BasePlayer.PlayerFlags.WantsSpeed, true);
// Note: Full speed modification requires additional work
}
if (mutation.Invisible) {
player.SetPlayerFlag(BasePlayer.PlayerFlags.Invisible, true);
}
activePlayerMutations[player.userID] = active;
// Visual effect
Effect.server.Run("assets/prefabs/locks/keylock/effects/lock.code.updated.prefab", player.transform.position, Vector3.zero);
SendReply(player, $"<color={mutation.Color}>🧬 MUTATION: {mutation.Name}!</color>");
SendReply(player, $"<color=yellow>{mutation.Description}</color> Duration: {config.MutationDurationSeconds / 60} minutes");
Server.Broadcast($"<color=purple>⚡ {player.displayName} has mutated into a {mutation.Name}!</color>");
Puts($"Player {player.displayName} mutated: {mutation.Name}");
}
private void AddGlowEffect(BaseEntity entity, string colorHex) {
// Apply glow effect using material change
var renderer = entity.GetComponentInChildren<Renderer>();
if (renderer != null) {
var glowMaterial = new Material(renderer.material);
glowMaterial.SetColor("_EmissionColor", HexToColor(colorHex));
glowMaterial.EnableKeyword("_EMISSION");
renderer.material = glowMaterial;
}
}
private Color HexToColor(string hex) {
hex = hex.TrimStart('#');
float r = int.Parse(hex.Substring(0, 2), System.Globalization.NumberStyles.HexNumber) / 255f;
float g = int.Parse(hex.Substring(2, 2), System.Globalization.NumberStyles.HexNumber) / 255f;
float b = int.Parse(hex.Substring(4, 2), System.Globalization.NumberStyles.HexNumber) / 255f;
return new Color(r, g, b);
}
private void OnEntityDeath(BaseCombatEntity entity, HitInfo info) {
// Handle mutated animal death
if (activeAnimalMutations.ContainsKey(entity)) {
var mutation = activeAnimalMutations[entity];
// Explosion on death
if (mutation.ExplodesOnDeath) {
Effect.server.Run("assets/prefabs/npc/cargo plane/effects/explosion_cargo.prefab", entity.transform.position, Vector3.zero);
// Damage nearby players
foreach (var player in BasePlayer.activePlayerList) {
if (Vector3.Distance(player.transform.position, entity.transform.position) < 10f) {
player.Hurt(50, DamageType.Explosion);
}
}
}
// Fire trail
if (mutation.LeavesFireTrail) {
Effect.server.Run("assets/bundled/prefabs/fire/fire.prefab", entity.transform.position, Vector3.zero);
}
// Drop multiplier
if (mutation.DropMultiplier > 1 && info != null && info.InitiatorPlayer != null) {
// Additional loot logic would go here
}
activeAnimalMutations.Remove(entity);
Puts($"Mutated {mutation.Name} died at {entity.transform.position}");
}
}
private void OnPlayerTick(BasePlayer player, float deltaTime) {
if (!config.Enabled) return;
if (player == null || player.IsDead()) return;
// Check mutation expiry
if (activePlayerMutations.ContainsKey(player.userID)) {
var mutation = activePlayerMutations[player.userID];
if (Time.realtimeSinceStartup >= mutation.EndTime) {
RemovePlayerMutation(player);
}
else {
// Apply radiation damage aura
if (mutation.Mutation.RadiationDamage > 0) {
foreach (var otherPlayer in BasePlayer.activePlayerList) {
if (otherPlayer != player && Vector3.Distance(player.transform.position, otherPlayer.transform.position) < 5f) {
otherPlayer.Hurt(mutation.Mutation.RadiationDamage * deltaTime, DamageType.Radiation);
}
}
}
}
}
}
private void RemovePlayerMutation(BasePlayer player) {
if (!activePlayerMutations.ContainsKey(player.userID)) return;
var mutation = activePlayerMutations[player.userID];
// Restore original stats
player.InitializeHealth(mutation.OriginalMaxHealth, mutation.OriginalMaxHealth);
player.SetPlayerFlag(BasePlayer.PlayerFlags.Invisible, false);
player.SetPlayerFlag(BasePlayer.PlayerFlags.WantsSpeed, false);
activePlayerMutations.Remove(player.userID);
SendReply(player, $"<color=yellow>🧬 Your mutation ({mutation.Mutation.Name}) has worn off.</color>");
}
#endregion
#region Commands
[ChatCommand("mutation")]
private void cmdMutation(BasePlayer player, string command, string[] args) {
if (activePlayerMutations.ContainsKey(player.userID)) {
var mutation = activePlayerMutations[player.userID];
float remaining = mutation.EndTime - Time.realtimeSinceStartup;
SendReply(player, $"<color=green>Active mutation: {mutation.Mutation.Name}</color>");
SendReply(player, $"Remaining: {remaining / 60:F1} minutes");
}
else {
SendReply(player, "You have no active mutation.");
SendReply(player, "Enter radiation zones to have a chance to mutate!");
}
}
[ConsoleCommand("mutation.give")]
private void cmdGiveMutation(ConsoleSystem.Arg args) {
if (args.Connection != null && !permission.UserHasPermission(args.Connection.UserId.ToString(), "mutationsystem.admin")) {
args.ReplyWith("No permission");
return;
}
if (args.Args == null || args.Args.Length < 2) {
args.ReplyWith("Usage: mutation.give <steamID> <mutationName>");
return;
}
ulong steamId = Convert.ToUInt64(args.Args[0]);
string mutationName = args.Args[1];
var player = BasePlayer.FindByID(steamId);
if (player == null) {
args.ReplyWith("Player not found");
return;
}
var mutation = config.PlayerMutations.FirstOrDefault(m => m.Name.ToLower() == mutationName.ToLower());
if (mutation == null) {
args.ReplyWith($"Mutation '{mutationName}' not found");
return;
}
var active = new ActiveMutation {
Mutation = mutation, EndTime = Time.realtimeSinceStartup + config.MutationDurationSeconds, OriginalMaxHealth = player.MaxHealth(), OriginalSpeed = 1f
}
;
activePlayerMutations[steamId] = active;
args.ReplyWith($"Gave mutation '{mutation.Name}' to {player.displayName}");
}
[ConsoleCommand("mutation.reload")]
private void cmdReload(ConsoleSystem.Arg args) {
if (args.Connection != null && !permission.UserHasPermission(args.Connection.UserId.ToString(), "mutationsystem.admin")) {
args.ReplyWith("No permission");
return;
}
LoadConfig();
args.ReplyWith("MutationSystem reloaded");
}
#endregion
}
}