Skip to content
RustPluginGenerator

How to make a Rust PvP damage multiplier plugin (global, per-weapon, headshot)

Scales damage players deal to other players using a global multiplier, per-weapon shortname overrides and an extra headshot factor. It runs in OnEntityTakeDamage(BasePlayer, HitInfo) and rewrites hitInfo.damageTypes before the hit is applied.

On a normal Rust server every player-vs-player fight uses vanilla damage numbers, which makes it hard to push longer fights, make specific guns weaker, or reward headshots without touching real weapon stats. This plugin solves that by scaling the damage in the damage event itself: OnEntityTakeDamage(BasePlayer player, HitInfo hitInfo) fires before the hit is applied, so the plugin can check both the victim and the attacker, confirm they are different players, and adjust hitInfo.damageTypes with ScaleAll.

Three layers of control are exposed in the config: a global PvP multiplier, a per-weapon override keyed by the weapon shortname from hitInfo.Weapon.ShortPrefabName (rifles, melee, explosives all work), and a separate headshot multiplier applied on top when hitInfo.isHeadshot is true. NPCs, structures, animals and environmental damage are left untouched. A /pvpcd command shows the current numbers so admins can verify a config change without reading the file.

The plugin code

PvPDamageMultiplier.cs
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;

namespace Oxide.Plugins
{
    [Info("PvP Damage Multiplier", "RustPluginGenerator", "1.0.0")]
    [Description("Scales player versus player damage with a global multiplier, per-weapon overrides and a headshot multiplier.")]
    public class PvPDamageMultiplier : RustPlugin
    {
        private const string PermUse = "pvpdamagemultiplier.use";

        private PluginConfig config;

        private class PluginConfig
        {
            [JsonProperty("Global multiplier")]
            public float GlobalMultiplier = 1.0f;

            [JsonProperty("Headshot multiplier")]
            public float HeadshotMultiplier = 1.0f;

            [JsonProperty("Minimum damage scale")]
            public float MinDamageScale = 0.1f;

            [JsonProperty("Maximum damage scale")]
            public float MaxDamageScale = 5.0f;

            [JsonProperty("Weapon multipliers (shortname)")]
            public Dictionary<string, float> WeaponMultipliers = new Dictionary<string, float>
            {
                ["rifle.ak"] = 1.0f,
                ["smg.2"] = 1.0f,
                ["shotgun.pump"] = 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>
            {
                ["Status"] = "PvP damage: global {0}x, headshot {1}x, {2} weapon overrides.",
                ["NoPermission"] = "You do not have permission to use this command."
            }, this);
        }

        private void Init()
        {
            permission.RegisterPermission(PermUse, this);
        }

        private void Unload()
        {
            SaveConfig();
        }

        private string Msg(string key, string userId = null, params object[] args) => string.Format(lang.GetMessage(key, this, userId), args);

        private object OnEntityTakeDamage(BasePlayer player, HitInfo hitInfo)
        {
            if (player == null || hitInfo == null || hitInfo.damageTypes == null) return null;
            if (player.IsNpc) return null;

            BasePlayer attacker = hitInfo.InitiatorPlayer;
            if (attacker == null || attacker.IsNpc || attacker == player) return null;

            float scale = config.GlobalMultiplier;

            AttackEntity weapon = hitInfo.Weapon;
            if (weapon != null && !string.IsNullOrEmpty(weapon.ShortPrefabName))
            {
                float overrideScale;
                if (config.WeaponMultipliers != null && config.WeaponMultipliers.TryGetValue(weapon.ShortPrefabName, out overrideScale))
                {
                    scale = overrideScale;
                }
            }

            if (hitInfo.isHeadshot) scale *= config.HeadshotMultiplier;

            scale = Mathf.Clamp(scale, config.MinDamageScale, config.MaxDamageScale);

            hitInfo.damageTypes.ScaleAll(scale);
            return null;
        }

        [ChatCommand("pvpcd")]
        private void CmdStatus(BasePlayer player, string command, string[] args)
        {
            if (player == null) return;
            if (!permission.UserHasPermission(player.UserIDString, PermUse))
            {
                player.ChatMessage(Msg("NoPermission", player.UserIDString));
                return;
            }

            int overrides = config.WeaponMultipliers != null ? config.WeaponMultipliers.Count : 0;
            player.ChatMessage(Msg("Status", player.UserIDString, config.GlobalMultiplier, config.HeadshotMultiplier, overrides));
        }
    }
}

Hooks used: OnEntityTakeDamage

Config file

Created automatically on first load at oxide/config/PvPDamageMultiplier.json.

PvPDamageMultiplier.json
{
  "Global multiplier": 1,
  "Headshot multiplier": 1,
  "Minimum damage scale": 0.1,
  "Maximum damage scale": 5,
  "Weapon multipliers (shortname)": {
    "rifle.ak": 1,
    "smg.2": 1,
    "shotgun.pump": 1
  }
}

Commands and permissions

Chat and console commands
CommandWhat it doesPermission
/pvpcdPrints the active global multiplier, headshot multiplier and the number of configured weapon overrides.pvpdamagemultiplier.use
Permissions
PermissionGrants
pvpdamagemultiplier.useAllows the player to run /pvpcd to inspect the active damage settings.

How the code works

  1. Restrict the hook to player-versus-player hits

    OnEntityTakeDamage(BasePlayer player, HitInfo hitInfo) only fires when the victim is a BasePlayer, but that still includes NPC scientists and damage with no attacker. Null-check hitInfo and hitInfo.InitiatorPlayer first, then compare hitInfo.InitiatorPlayer == player to bail out on self damage such as fall or bleed caused by the player's own actions. Finally skip when player.IsNpc or hitInfo.InitiatorPlayer.IsNpc is true so PvE fights stay vanilla.

  2. Resolve the weapon shortname for overrides

    hitInfo.Weapon is an AttackEntity; its ShortPrefabName is the shortname used as the config key (for example rifle.ak). Melee hits, thrown explosives and the hotbar weapon all pass through this field, so long as the method name is checked for null before reading ShortPrefabName. When Weapon is null (some ambient damage) the plugin falls back to the global multiplier only, which keeps the code safe.

  3. Apply global, weapon and headshot multipliers in order

    config.GlobalMultiplier is read first, then the dictionary config.WeaponMultipliers is queried by shortname and, if present, used instead of the global value. If hitInfo.isHeadshot is true the result is multiplied by config.HeadshotMultiplier. The final value is clamped between the two config limits MinDamageScale and MaxDamageScale so a mistyped 5.0 cannot produce a one-shot weapon. hitInfo.damageTypes.ScaleAll(scale) then rewrites every damage type in the hit.

  4. Keep the global override readable in the config

    The nested PluginConfig class holds GlobalMultiplier, HeadshotMultiplier and Dictionary<string, float> WeaponMultipliers with [JsonProperty] names. LoadConfig reads the file, re-creates defaults on any exception and calls SaveConfig. Only rifle.ak, smg.2 and shotgun.pump ship with sample overrides so admins can see the shape of the dictionary and add their own entries.

  5. Expose the values for quick checks

    [ChatCommand("pvpcd")] runs a permission-checked method that formats Msg("Status", ...) with the three configured values. Messages live in LoadDefaultMessages so the text can be translated. There is no hot-reload command: change the config, run oxide.reload PvPDamageMultiplier, and the new numbers are active immediately.

  6. Clean up on unload

    The plugin has no timers or CUI, so Unload just calls SaveConfig in case defaults were regenerated while running. Destroy any timer reference you add later in this same method; Oxide will call Unload automatically on oxide.unload PvPDamageMultiplier and on server shutdown.

Install it on your server

  1. Save PvPDamageMultiplier.cs

    Keep the file name exactly as the class name. Oxide matches them.
  2. 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.
  3. Edit the config if you want

    On first load the default config is written to oxide/config/PvPDamageMultiplier.json (Carbon: carbon/configs/PvPDamageMultiplier.json). After editing, reload it:oxide.reload PvPDamageMultiplier c.reload PvPDamageMultiplier # Carbon
  4. Grant the permission

    Give it to every player, or swap default for a group such as vip:oxide.grant group default pvpdamagemultiplier.use c.grant group default pvpdamagemultiplier.use # Carbon

Variations

Each one opens the generator with a ready prompt you can tweak.

  • Per-weapon multipliers by weapon category

    Scale all guns together via the item category instead of listing every shortname.

    Generate this version
  • Apply multipliers only inside building-protected areas

    Use a simpler fight rule: only scale damage near a tool cupboard.

    Generate this version
  • Add per-player damage permissions

    Let donators take less PvP damage via a permission group.

    Generate this version

FAQ

Does this affect damage to NPCs, animals or building blocks?

No. The hook used here is the BasePlayer overload, so it only sees damage where the victim is a player. NPC scientists are still BasePlayer instances, so the method checks IsNpc on both sides and leaves those hits at vanilla values.

Why is my per-weapon override not applied?

The key must match AttackEntity.ShortPrefabName, which is usually the item shortname but not always (for example some melee prefabs differ from the item shortname). Test the weapon in-game and check that the config key matches the prefab name shown when the weapon hits.

Do the multipliers stack with headshot damage?

Yes. The order is: pick the weapon override or global value, then multiply by HeadshotMultiplier if hitInfo.isHeadshot is true, then clamp to MinDamageScale and MaxDamageScale. A 1.2 weapon override with a 1.5 headshot multiplier results in 1.8x total.

How do I install it on Oxide or Carbon?

Drop PvPDamageMultiplier.cs into oxide/plugins, wait for compilation, then edit oxide/config/PvPDamageMultiplier.json and run oxide.reload PvPDamageMultiplier. Carbon loads the same file from its plugins folder without changes.

Does it work with decay, raid explosions or environmental damage?

Explosions only route through this hook when the attacker is a player and the victim is a player, so C4 on a wall and decay damage stay untouched. Explosive damage thrown by a player at another player is scaled like any other hit.

Customize it for your server

Change the reward, add a cooldown, restrict it to VIPs. Start from this prompt and edit anything.

Prompt: Make a Rust Oxide PvP damage multiplier plugin with a global multiplier of 1.0, headshot multiplier 1.0 and sample per-weapon overrides for rifle.ak, smg.2 and shotgun.pump, plus a /pvpcd status command behind the pvpdamagemultiplier.use permission.
Customize for my server

Edit the prompt on the next screen. 2 free plugins a month, no card.

Last updated Oct 26, 2026.

Customize pvp damage multiplier

Customize