C#:
using Oxide.Core;
using UnityEngine;
using System.Collections.Generic;
using Newtonsoft.Json;
namespace Oxide.Plugins
{
[Info("RocketTiers", "MaxSilverhand", "1.1.0")]
[Description("Automatically sets rocket launcher capacity based on skin ID")]
class RocketTiers : RustPlugin
{
// Configuration class
private class PluginConfig
{
[JsonProperty(PropertyName = "Launcher Shortname")]
public string LauncherShortname { get; set; } = "rocket.launcher";
[JsonProperty(PropertyName = "Tier 1 - Skin ID")]
public ulong Tier1Skin { get; set; } = 3717048444;
[JsonProperty(PropertyName = "Tier 1 - Capacity")]
public int Tier1Capacity { get; set; } = 5;
[JsonProperty(PropertyName = "Tier 2 - Skin ID")]
public ulong Tier2Skin { get; set; } = 3717048386;
[JsonProperty(PropertyName = "Tier 2 - Capacity")]
public int Tier2Capacity { get; set; } = 10;
[JsonProperty(PropertyName = "Tier 3 - Skin ID")]
public ulong Tier3Skin { get; set; } = 3717048331;
[JsonProperty(PropertyName = "Tier 3 - Capacity")]
public int Tier3Capacity { get; set; } = 20;
[JsonProperty(PropertyName = "Rocket Ammo Type")]
public string RocketAmmoType { get; set; } = "ammo.rocket.basic";
[JsonProperty(PropertyName = "Give Rockets With Launcher")]
public bool GiveRocketsWithLauncher { get; set; } = true;
[JsonProperty(PropertyName = "Command Cooldown (Seconds)")]
public int CommandCooldown { get; set; } = 5;
}
private PluginConfig config;
private Dictionary<ulong, int> skinCapacityMap = new Dictionary<ulong, int>();
private Dictionary<ulong, float> playerCooldowns = new Dictionary<ulong, float>();
// Load configuration
protected override void LoadConfig()
{
base.LoadConfig();
config = Config.ReadObject<PluginConfig>();
if (config == null)
{
LoadDefaultConfig();
}
SaveConfig();
BuildSkinMap();
}
protected override void LoadDefaultConfig()
{
config = new PluginConfig();
PrintWarning("Default configuration has been created.");
}
protected override void SaveConfig()
{
Config.WriteObject(config);
}
// Build skin to capacity mapping
private void BuildSkinMap()
{
skinCapacityMap.Clear();
skinCapacityMap[config.Tier1Skin] = config.Tier1Capacity;
skinCapacityMap[config.Tier2Skin] = config.Tier2Capacity;
skinCapacityMap[config.Tier3Skin] = config.Tier3Capacity;
Puts($"Loaded {skinCapacityMap.Count} rocket tiers");
Puts($"Tier 1: Skin {config.Tier1Skin} -> {config.Tier1Capacity} rockets");
Puts($"Tier 2: Skin {config.Tier2Skin} -> {config.Tier2Capacity} rockets");
Puts($"Tier 3: Skin {config.Tier3Skin} -> {config.Tier3Capacity} rockets");
}
void Init()
{
// Register permissions with plugin name prefix
permission.RegisterPermission("rockettiers.tier1", this);
permission.RegisterPermission("rockettiers.tier2", this);
permission.RegisterPermission("rockettiers.tier3", this);
}
// HOOK: When an item is created
void OnItemCreated(Item item)
{
if (item == null || item.info.shortname != config.LauncherShortname) return;
if (skinCapacityMap.ContainsKey(item.skin))
{
int capacity = skinCapacityMap[item.skin];
Puts($"OnItemCreated: Found skin {item.skin} -> Setting capacity to {capacity}");
ApplyCapacityToItem(item);
}
}
// HOOK: When item is equipped
void OnItemEquipped(Item item, BasePlayer player)
{
if (item == null || item.info.shortname != config.LauncherShortname) return;
if (skinCapacityMap.ContainsKey(item.skin))
{
int capacity = skinCapacityMap[item.skin];
Puts($"OnItemEquipped: Player {player.displayName} equipped skin {item.skin} -> Capacity: {capacity}");
ApplyCapacityToItem(item);
}
}
// HOOK: Intercept reload attempts
void OnReloadWeapon(BasePlayer player, BaseProjectile projectile)
{
if (projectile == null || player == null) return;
Item activeItem = player.GetActiveItem();
if (activeItem == null || activeItem.info.shortname != config.LauncherShortname) return;
if (skinCapacityMap.ContainsKey(activeItem.skin))
{
int capacity = skinCapacityMap[activeItem.skin];
var magazine = projectile.primaryMagazine;
if (magazine == null) return;
// Set capacity
if (magazine.capacity != capacity)
{
magazine.capacity = capacity;
}
// Check if we need to reload
int needed = capacity - magazine.contents;
if (needed <= 0) return;
// Take rockets from inventory
int loaded = TakeRocketsFromInventory(player, needed);
if (loaded > 0)
{
magazine.contents += loaded;
Puts($"Loaded {loaded} rockets into {player.displayName}'s launcher (Total: {magazine.contents}/{capacity})");
SendReply(player, $"Loaded {loaded} rockets! ({magazine.contents}/{capacity})");
}
else
{
// No rockets in inventory - prevent free reload
SendReply(player, "You don't have any rockets in your inventory to reload!");
Puts($"RELOAD BLOCKED: {player.displayName} has no rockets in inventory");
}
}
}
// Take rockets from player's inventory
private int TakeRocketsFromInventory(BasePlayer player, int amount)
{
if (player == null || amount <= 0) return 0;
int taken = 0;
// Check main inventory
foreach (var item in player.inventory.containerMain.itemList)
{
if (item != null && item.info.shortname == config.RocketAmmoType)
{
int canTake = Mathf.Min(item.amount, amount - taken);
if (canTake > 0)
{
int oldAmount = item.amount;
item.UseItem(canTake);
int used = oldAmount - item.amount;
taken += used;
Puts($"Took {used} rockets from main inventory");
if (taken >= amount) break;
}
}
}
// If still need more, check belt
if (taken < amount)
{
foreach (var item in player.inventory.containerBelt.itemList)
{
if (item != null && item.info.shortname == config.RocketAmmoType)
{
int canTake = Mathf.Min(item.amount, amount - taken);
if (canTake > 0)
{
int oldAmount = item.amount;
item.UseItem(canTake);
int used = oldAmount - item.amount;
taken += used;
Puts($"Took {used} rockets from belt");
if (taken >= amount) break;
}
}
}
}
return taken;
}
// Count rockets in player's inventory
private int CountRocketsInInventory(BasePlayer player)
{
if (player == null) return 0;
int count = 0;
// Check main inventory
foreach (var item in player.inventory.containerMain.itemList)
{
if (item != null && item.info.shortname == config.RocketAmmoType)
{
count += item.amount;
}
}
// Check belt
foreach (var item in player.inventory.containerBelt.itemList)
{
if (item != null && item.info.shortname == config.RocketAmmoType)
{
count += item.amount;
}
}
return count;
}
// HOOK: When an item is moved
void OnItemMoved(Item item, BasePlayer player)
{
if (item == null || item.info.shortname != config.LauncherShortname) return;
if (skinCapacityMap.ContainsKey(item.skin))
{
timer.Once(0.05f, () => {
ApplyCapacityToItem(item);
});
}
}
// HOOK: When a player's inventory changes
void OnInventoryChanged(BasePlayer player)
{
if (player == null) return;
timer.Once(0.1f, () => {
CheckPlayerInventory(player);
});
}
// Check player's entire inventory for rockets
private void CheckPlayerInventory(BasePlayer player)
{
if (player == null) return;
bool foundAny = false;
// Check main inventory
if (player.inventory.containerMain != null)
{
foreach (var item in player.inventory.containerMain.itemList)
{
if (item != null && item.info.shortname == config.LauncherShortname)
{
if (skinCapacityMap.ContainsKey(item.skin))
{
foundAny = true;
ApplyCapacityToItem(item);
}
}
}
}
// Check belt
if (player.inventory.containerBelt != null)
{
foreach (var item in player.inventory.containerBelt.itemList)
{
if (item != null && item.info.shortname == config.LauncherShortname)
{
if (skinCapacityMap.ContainsKey(item.skin))
{
foundAny = true;
ApplyCapacityToItem(item);
}
}
}
}
if (foundAny)
{
Puts($"Checked inventory for {player.displayName} - Found and fixed rockets");
}
}
// Apply capacity to item
private void ApplyCapacityToItem(Item item)
{
if (item == null) return;
int capacity = 0;
if (!skinCapacityMap.TryGetValue(item.skin, out capacity)) return;
var heldEntity = item.GetHeldEntity() as BaseProjectile;
if (heldEntity != null)
{
var magazine = heldEntity.primaryMagazine;
if (magazine != null)
{
if (magazine.capacity != capacity)
{
magazine.capacity = capacity;
Puts($"Applied capacity {capacity} to item (current ammo: {magazine.contents})");
}
}
}
}
// Give rockets to player
private void GiveRockets(BasePlayer player, int amount)
{
if (player == null || amount <= 0) return;
Item rocketItem = ItemManager.CreateByName(config.RocketAmmoType, amount);
if (rocketItem != null)
{
player.inventory.GiveItem(rocketItem);
Puts($"Gave {amount} rockets to {player.displayName}");
}
}
// Give launcher to player
private void GiveLauncher(BasePlayer player, ulong skinID, int capacity, string tierName, string permissionName)
{
if (player == null) return;
// Check permission
if (!string.IsNullOrEmpty(permissionName) && !permission.UserHasPermission(player.UserIDString, permissionName))
{
SendReply(player, $"You don't have permission to use this command! (Requires: {permissionName})");
return;
}
// Check cooldown
if (playerCooldowns.ContainsKey(player.userID))
{
float timeLeft = playerCooldowns[player.userID] - Time.time;
if (timeLeft > 0)
{
SendReply(player, $"Please wait {Mathf.CeilToInt(timeLeft)} seconds before using this command again!");
return;
}
}
// Create the launcher
Item launcher = ItemManager.CreateByName(config.LauncherShortname, 1, skinID);
if (launcher != null)
{
// Set display name
launcher.name = tierName;
// Apply capacity
ApplyCapacityToItem(launcher);
// Give to player
player.inventory.GiveItem(launcher);
// Give rockets if enabled
if (config.GiveRocketsWithLauncher)
{
GiveRockets(player, capacity);
}
// Set cooldown
playerCooldowns[player.userID] = Time.time + config.CommandCooldown;
SendReply(player, $"You received a {tierName} with {capacity} rocket capacity!");
SendReply(player, $"Make sure you have rockets in your inventory to reload!");
}
else
{
SendReply(player, "Error: Could not create rocket launcher!");
}
}
// ============================================
// PLAYER CHAT COMMANDS
// ============================================
[ChatCommand("rocket1")]
void GiveRocketTier1(BasePlayer player, string command, string[] args)
{
if (player == null) return;
GiveLauncher(player, config.Tier1Skin, config.Tier1Capacity, "Rocket Tier 1", "rockettiers.tier1");
}
[ChatCommand("rocket2")]
void GiveRocketTier2(BasePlayer player, string command, string[] args)
{
if (player == null) return;
GiveLauncher(player, config.Tier2Skin, config.Tier2Capacity, "Rocket Tier 2", "rockettiers.tier2");
}
[ChatCommand("rocket3")]
void GiveRocketTier3(BasePlayer player, string command, string[] args)
{
if (player == null) return;
GiveLauncher(player, config.Tier3Skin, config.Tier3Capacity, "Rocket Tier 3", "rockettiers.tier3");
}
[ChatCommand("rocketlist")]
void ListRockets(BasePlayer player, string command, string[] args)
{
if (player == null) return;
SendReply(player, "=== Rocket Tiers ===");
SendReply(player, $"Tier 1: {config.Tier1Capacity} rockets - Skin: {config.Tier1Skin} - Command: /rocket1");
SendReply(player, $"Tier 2: {config.Tier2Capacity} rockets - Skin: {config.Tier2Skin} - Command: /rocket2");
SendReply(player, $"Tier 3: {config.Tier3Capacity} rockets - Skin: {config.Tier3Skin} - Command: /rocket3");
SendReply(player, "Type /rocket1, /rocket2, or /rocket3 to receive a launcher");
SendReply(player, "You need rockets in your inventory to reload!");
}
// ============================================
// ADMIN COMMANDS
// ============================================
[ConsoleCommand("rocket.fix")]
void FixRocketCommand(ConsoleSystem.Arg arg)
{
if (arg.IsAdmin == false) return;
if (arg.Args == null || arg.Args.Length < 1)
{
arg.ReplyWith("Usage: rocket.fix <playerName>");
return;
}
BasePlayer target = BasePlayer.Find(arg.Args[0].ToString());
if (target == null)
{
arg.ReplyWith($"Player '{arg.Args[0]}' not found!");
return;
}
CheckPlayerInventory(target);
arg.ReplyWith($"Checked and fixed rockets for {target.displayName}");
}
[ConsoleCommand("rocket.check")]
void CheckRocketCommand(ConsoleSystem.Arg arg)
{
if (arg.IsAdmin == false) return;
if (arg.Args == null || arg.Args.Length < 1)
{
arg.ReplyWith("Usage: rocket.check <playerName>");
return;
}
BasePlayer target = BasePlayer.Find(arg.Args[0].ToString());
if (target == null)
{
arg.ReplyWith($"Player '{arg.Args[0]}' not found!");
return;
}
arg.ReplyWith($"=== Rocket Check for {target.displayName} ===");
int found = 0;
found += CheckContainerForReport(arg, target.inventory.containerMain);
found += CheckContainerForReport(arg, target.inventory.containerBelt);
found += CheckContainerForReport(arg, target.inventory.containerWear);
if (found == 0)
{
arg.ReplyWith("No rocket launchers found in inventory!");
}
int rocketCount = CountRocketsInInventory(target);
arg.ReplyWith($"Rockets in inventory: {rocketCount}");
}
private int CheckContainerForReport(ConsoleSystem.Arg arg, ItemContainer container)
{
if (container == null) return 0;
int count = 0;
foreach (var item in container.itemList)
{
if (item != null && item.info.shortname == config.LauncherShortname)
{
count++;
arg.ReplyWith($"--- Launcher ---");
arg.ReplyWith($"Skin ID: {item.skin}");
var heldEntity = item.GetHeldEntity() as BaseProjectile;
if (heldEntity != null)
{
var magazine = heldEntity.primaryMagazine;
if (magazine != null)
{
arg.ReplyWith($"Current Capacity: {magazine.capacity}");
arg.ReplyWith($"Current Ammo: {magazine.contents}");
}
}
if (skinCapacityMap.ContainsKey(item.skin))
{
int capacity = skinCapacityMap[item.skin];
arg.ReplyWith($"Expected Capacity: {capacity}");
int currentCapacity = heldEntity?.primaryMagazine?.capacity ?? 0;
arg.ReplyWith($"Status: {(capacity == currentCapacity ? "✅ CORRECT" : "❌ NEEDS FIX")}");
}
else
{
arg.ReplyWith("⚠️ This skin is NOT configured!");
}
}
}
return count;
}
[ConsoleCommand("rocket.reload")]
void ReloadConfigCommand(ConsoleSystem.Arg arg)
{
if (arg.IsAdmin == false) return;
LoadConfig();
arg.ReplyWith("RocketTiers config reloaded!");
}
}
}