How to make a Rust NPC health multiplier plugin (per-prefab scaling)
Scales the health of scientists and animals when they spawn by reading a per-prefab multiplier from the config, using the OnEntitySpawned hook to detect NPC entities and heal them to the scaled target.
Default Rust NPC health rarely matches a modded server. Admins running PvE, hardcore or custom scientist events want scientists that take more bullets, or animals that die faster so hunting is not a grind. The problem is that Rust spawns scientists and animals from many different prefabs, and health is baked into each one at spawn time.
This plugin listens for OnEntitySpawned, checks whether the spawned entity is a ScientistNPC, BaseAnimalNPC or ScarecrowNPC, and looks up a multiplier for its ShortPrefabName. If no exact entry exists it falls back to Default Multiplier. The plugin then computes MaxHealth() * multiplier on the BaseCombatEntity and calls Heal so the NPC starts at the adjusted value instead of its vanilla amount.
Because matching is done on prefab name, you can scale one scientist prefab differently from another, or leave bears and boars at different values. Config edits save to disk, so no server restart is needed.
The plugin code
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Npc Health Multiplier", "RustPluginGenerator", "1.0.0")]
[Description("Scales scientist and animal health on spawn using per-prefab multipliers.")]
public class NpcHealthMultiplier : RustPlugin
{
private const string PermAdmin = "npchealthmultiplier.admin";
private const int SeenCap = 5000;
private PluginConfig config;
private readonly HashSet<ulong> seen = new HashSet<ulong>();
private class PluginConfig
{
[JsonProperty("Default multiplier")]
public float DefaultMultiplier { get; set; } = 1.0f;
[JsonProperty("Prefab multipliers")]
public Dictionary<string, float> PrefabMultipliers { get; set; } = new Dictionary<string, float>
{
["scientistnpc_heavy"] = 1.5f,
["scientistnpc_roam"] = 1.25f,
["bear"] = 0.75f,
["boar"] = 1.0f
};
}
protected override void LoadDefaultConfig() => config = new PluginConfig();
protected override void LoadConfig()
{
base.LoadConfig();
try
{
config = Config.ReadObject<PluginConfig>();
if (config == null) throw new Exception();
}
catch
{
PrintWarning("Configuration file is invalid, using defaults");
LoadDefaultConfig();
}
SaveConfig();
}
protected override void SaveConfig() => Config.WriteObject(config);
protected override void LoadDefaultMessages()
{
lang.RegisterMessages(new Dictionary<string, string>
{
["NoPerm"] = "You do not have permission to use this command.",
["Set"] = "Set multiplier for {0} to {1}.",
["Default"] = "Default multiplier set to {0}.",
["List Header"] = "NPC health multipliers (default {0}):",
["List Row"] = "{0} = {1}",
["Usage Set"] = "Usage: /npchealth.set <prefab> <multiplier>",
["Usage Default"] = "Usage: /npchealth.default <multiplier>",
["Bad Number"] = "{0} is not a valid number.",
["Out Of Range"] = "Multiplier must be between 0.1 and 50."
}, this);
}
private void Init()
{
permission.RegisterPermission(PermAdmin, this);
}
private void Unload()
{
seen.Clear();
}
private string Msg(string key, string userId = null, params object[] args) =>
string.Format(lang.GetMessage(key, this, userId), args);
private void OnEntitySpawned(BaseNetworkable networkable)
{
if (networkable == null || networkable.IsDestroyed) return;
var combat = networkable as BaseCombatEntity;
if (combat == null) return;
if (!(networkable is ScientistNPC) && !(networkable is BaseAnimalNPC) && !(networkable is ScarecrowNPC))
return;
var id = networkable.net?.ID.Value ?? 0;
if (id == 0 || seen.Contains(id)) return;
if (seen.Count >= SeenCap) seen.Clear();
seen.Add(id);
var prefab = networkable.ShortPrefabName;
float multiplier = config.DefaultMultiplier;
if (!string.IsNullOrEmpty(prefab) && config.PrefabMultipliers.TryGetValue(prefab, out var specific))
multiplier = specific;
if (Mathf.Approximately(multiplier, 1f)) return;
if (multiplier <= 0f) multiplier = 0.1f;
var target = Mathf.Max(1f, combat.MaxHealth() * multiplier);
if (combat.health >= target) return;
combat.Heal(target - combat.health);
}
[ChatCommand("npchealth.set")]
private void CmdSet(BasePlayer player, string command, string[] args)
{
if (!permission.UserHasPermission(player.UserIDString, PermAdmin))
{
SendReply(player, Msg("NoPerm", player.UserIDString));
return;
}
if (args == null || args.Length < 2)
{
SendReply(player, Msg("Usage Set", player.UserIDString));
return;
}
if (!float.TryParse(args[1], out var multiplier))
{
SendReply(player, Msg("Bad Number", player.UserIDString, args[1]));
return;
}
if (multiplier < 0.1f || multiplier > 50f)
{
SendReply(player, Msg("Out Of Range", player.UserIDString));
return;
}
var prefab = args[0].ToLowerInvariant();
config.PrefabMultipliers[prefab] = multiplier;
SaveConfig();
SendReply(player, Msg("Set", player.UserIDString, prefab, multiplier));
}
[ChatCommand("npchealth.default")]
private void CmdDefault(BasePlayer player, string command, string[] args)
{
if (!permission.UserHasPermission(player.UserIDString, PermAdmin))
{
SendReply(player, Msg("NoPerm", player.UserIDString));
return;
}
if (args == null || args.Length < 1)
{
SendReply(player, Msg("Usage Default", player.UserIDString));
return;
}
if (!float.TryParse(args[0], out var multiplier))
{
SendReply(player, Msg("Bad Number", player.UserIDString, args[0]));
return;
}
if (multiplier < 0.1f || multiplier > 50f)
{
SendReply(player, Msg("Out Of Range", player.UserIDString));
return;
}
config.DefaultMultiplier = multiplier;
SaveConfig();
SendReply(player, Msg("Default", player.UserIDString, multiplier));
}
[ChatCommand("npchealth.list")]
private void CmdList(BasePlayer player, string command, string[] args)
{
if (!permission.UserHasPermission(player.UserIDString, PermAdmin))
{
SendReply(player, Msg("NoPerm", player.UserIDString));
return;
}
SendReply(player, Msg("List Header", player.UserIDString, config.DefaultMultiplier));
foreach (var pair in config.PrefabMultipliers.OrderBy(p => p.Key))
SendReply(player, Msg("List Row", player.UserIDString, pair.Key, pair.Value));
}
}
}Hooks used: OnEntitySpawned
Config file
Created automatically on first load at oxide/config/NpcHealthMultiplier.json.
{
"Default multiplier": 1,
"Prefab multipliers": {
"scientistnpc_heavy": 1.5,
"scientistnpc_roam": 1.25,
"bear": 0.75,
"boar": 1
}
}Commands and permissions
| Command | What it does | Permission |
|---|---|---|
/npchealth.set <prefab> <multiplier> | Adds or updates a per-prefab multiplier and writes the config. | npchealthmultiplier.admin |
/npchealth.default <multiplier> | Sets the fallback multiplier used for NPCs without a specific entry. | npchealthmultiplier.admin |
/npchealth.list | Prints the current multiplier table to chat. | npchealthmultiplier.admin |
| Permission | Grants |
|---|---|
npchealthmultiplier.admin | Grants access to the /npchealth.* chat commands. |
How the code works
Detect NPC spawns
The plugin registers
private void OnEntitySpawned(BaseNetworkable networkable). Every spawned networkable passes through it, so the first checks reject what cannot be scaled: null,IsDestroyed, and casts toBaseCombatEntitywithas. Casting toBaseCombatEntitygives youMaxHealth(),healthandHeal(float)without touching player or building classes.Filter to scientists and animals
Only combat NPCs are scaled. The plugin checks
networkable is ScientistNPC,networkable is BaseAnimalNPCandnetworkable is ScarecrowNPC. Players, cars, doors and building blocks are ignored even if they areBaseCombatEntity. This keeps the plugin from touching prefabs that share the spawn hook but should never change health, such as deployables that happen to be combat entities.Resolve the multiplier
The prefab's
ShortPrefabNameis looked up in thePrefab Multipliersdictionary fromPluginConfig. An exact match wins. If none exists,config.DefaultMultiplieris used. The method returns early when the multiplier is approximately1.0, so vanilla NPCs are untouched and no network update is sent.Apply the scaled health
BaseCombatEntityhas no public health setter, so the plugin computesMathf.Max(1f, combat.MaxHealth() * multiplier)and callscombat.Heal(target - combat.health)only when the NPC is below the target. A multiplier of0.5on a bear with a 400 base drops its spawned health to 200. Values below zero are clamped to0.1fso a bad config cannot zero out an NPC.Avoid compounding on the same entity
The plugin keeps a
HashSet<ulong>calledseenofnetworkable.net.ID.Valuevalues it already processed, so a second spawn notification for the same entity is ignored. When the set reachesSeenCap(5000 entries) it is cleared, which bounds memory on long-running maps.Unloadclears the set as well.Manage the config in game
/npchealth.set <prefab> <multiplier>writes toPrefab Multipliersand saves withSaveConfig()./npchealth.defaultchangesDefault Multiplier, and/npchealth.listprints the current table ordered by prefab key. All three are chat commands guarded bynpchealthmultiplier.admin, registered inInit(). Changes apply to newly spawned NPCs; existing ones keep their current health until they die or are replaced.
Install it on your server
Save NpcHealthMultiplier.cs
Keep the file name exactly as the class name. Oxide matches them.Upload it to the plugins folder
Oxide:oxide/plugins/. Carbon:carbon/plugins/. The server compiles and loads it within a few seconds, no restart needed.Edit the config if you want
On first load the default config is written tooxide/config/NpcHealthMultiplier.json(Carbon:carbon/configs/NpcHealthMultiplier.json). After editing, reload it:oxide.reload NpcHealthMultiplier c.reload NpcHealthMultiplier # CarbonGrant the permission
Give it to every player, or swapdefaultfor a group such asvip:oxide.grant group default npchealthmultiplier.admin c.grant group default npchealthmultiplier.admin # Carbon
Variations
Each one opens the generator with a ready prompt you can tweak.
Different multiplier by day phase
Scale scientist health up at night so PvE servers get harder after dark.
Generate this versionHealth scaling by distance from spawn
Nerf NPCs near spawn and buff them at the far side of the map.
Generate this versionKill reward tied to health
Award scrap proportional to the health multiplier when a scaled NPC dies.
Generate this version
FAQ
Does this change NPC health that already spawned before the plugin loaded?
No. Scaling happens in OnEntitySpawned, so only NPCs that spawn after the plugin loads (or after the config is saved) get the new health. Restart the server or trigger a wave for existing NPCs to pick up the new values.
Which prefab names can I use?
Use the ShortPrefabName value, not the asset path. Common examples are scientistnpc_heavy, scientistnpc_roam and bear. Spawn one NPC and check its short prefab name before you add a row, since exact matching means a typo silently falls back to the default multiplier.
How do I install this on Oxide or Carbon?
Save the file as NpcHealthMultiplier.cs inside oxide/plugins, then reload the plugin from the server console or the admin console. Carbon loads Oxide C# plugins from the same folder. The plugin creates oxide/config/NpcHealthMultiplier.json with defaults on first load.
Will a multiplier of 1.0 change anything?
No. The plugin skips the heal entirely when the resolved multiplier is approximately 1.0, so vanilla NPCs are untouched. This is why the default multiplier ships at 1.0 and you opt individual prefabs in.
Does the scaled health show to players during the fight?
Yes. Heal raises health to the scaled target and the change is sent over the network, so clients see the higher health bar while fighting the NPC. Loot tables are unaffected unless another plugin modifies them.
Customize it for your server
Change the reward, add a cooldown, restrict it to VIPs. Start from this prompt and edit anything.
Edit the prompt on the next screen. 2 free plugins a month, no card.
More npcs plugins
- Animal spawn commandAdds a permission-gated /animal <species> [count] chat command that spawns vanilla animals in front of the player, with a per-command cap, aโฆ
- Custom NPC lootRewrites the items inside corpses left by configured NPCs, using a weighted per-prefab loot table.OnServerInitializedOnCorpsePopulate
- NPC free zonesDefines named world zones where newly spawned scientists and animals are deleted immediately.OnEntitySpawned
Last updated Oct 26, 2026.
Customize npc health multiplier
Customize