From 6b15d68071903026b8c76d98b785e12c13336635 Mon Sep 17 00:00:00 2001 From: wtclaude Date: Thu, 8 Oct 2026 23:53:01 -0500 Subject: [PATCH] fix(examples): each example NPC its own outfit, every item at full durability (D323, D324) The 9d player walk found the example kits looked alike and shipped broken armour. - D323: the raider wears scrap armour, the camp guard metal, the sniper hide, the Juggernaut heavy plate. Weapons are unchanged. - D324: Kits sets an item's condition straight from its file, and the writer put 0 on armour (heavy plate 0 of 1000) and a flat 100 on weapons (an M249's maximum is 500). Each item is now written at this Rust's own maximum for it, read from the item definition; 0 where the item has none. - The harness checks it: s6.examples.fullCondition. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY --- plugin/RunicNPC.cs | 37 +++++++++++++++++++++++++++---------- tools/RunicNpcTest.cs | 12 ++++++++++++ 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/plugin/RunicNPC.cs b/plugin/RunicNPC.cs index c406d32..25a8737 100644 --- a/plugin/RunicNPC.cs +++ b/plugin/RunicNPC.cs @@ -4126,8 +4126,9 @@ namespace Oxide.Plugins /// Placements wait while Kits reloads with the example kits (D283 reloads RunicNPC with it). private bool _holdForKits; - private static JObject ExItem(string shortname, int amount, int position, float condition = 0f) => - JObject.FromObject(new { Shortname = shortname, Skin = 0UL, Amount = amount, Condition = condition, MaxCondition = condition, Ammo = 0, Position = position, Frequency = -1 }); + /// Condition is filled in when the kit is written, from this Rust's item definition (D324). + private static JObject ExItem(string shortname, int amount, int position) => + JObject.FromObject(new { Shortname = shortname, Skin = 0UL, Amount = amount, Condition = 0f, MaxCondition = 0f, Ammo = 0, Position = position, Frequency = -1 }); private static JObject ExKit(string name, JObject[] main, JObject[] wear, JObject[] belt) => new JObject { @@ -4139,17 +4140,24 @@ namespace Oxide.Plugins private static JObject[] Wear(params string[] items) => items.Select((s, i) => ExItem(s, 1, i)).ToArray(); - /// D289: the four kits. A short name this Rust does not know is left out with a warning. + /// + /// D289: the four kits, each in its own outfit (D323): the raider in scrap armour, the camp guard in metal, + /// the sniper in hide, the Juggernaut in heavy plate. A short name this Rust does not know is left out with + /// a warning. + /// private static Dictionary ExampleKits() => new Dictionary { ["rnpc_raider"] = ExKit("rnpc_raider", new[] { ExItem("ammo.rifle", 120, 0) }, - Wear("hoodie", "pants", "shoes.boots", "mask.bandana"), new[] { ExItem("rifle.semiauto", 1, 0, 100f) }), + Wear("coffeecan.helmet", "roadsign.jacket", "roadsign.kilt", "hoodie", "pants", "shoes.boots", "burlap.gloves"), + new[] { ExItem("rifle.semiauto", 1, 0) }), ["rnpc_campguard"] = ExKit("rnpc_campguard", new[] { ExItem("ammo.pistol", 200, 0) }, - Wear("metal.facemask", "metal.plate.torso", "hoodie", "pants", "shoes.boots"), new[] { ExItem("smg.thompson", 1, 0, 100f) }), + Wear("metal.facemask", "metal.plate.torso", "tshirt.long", "pants", "shoes.boots", "roadsign.gloves"), + new[] { ExItem("smg.thompson", 1, 0) }), ["rnpc_sniper"] = ExKit("rnpc_sniper", new[] { ExItem("ammo.rifle", 60, 0) }, - Wear("hat.boonie", "hoodie", "pants", "shoes.boots"), new[] { ExItem("rifle.bolt", 1, 0, 100f) }), + Wear("hat.boonie", "mask.balaclava", "attire.hide.poncho", "attire.hide.pants", "attire.hide.boots"), + new[] { ExItem("rifle.bolt", 1, 0) }), ["rnpc_juggernaut"] = ExKit("rnpc_juggernaut", new[] { ExItem("ammo.rifle", 300, 0) }, - Wear("heavy.plate.helmet", "heavy.plate.jacket", "heavy.plate.pants", "shoes.boots"), new[] { ExItem("lmg.m249", 1, 0, 100f) }) + Wear("heavy.plate.helmet", "heavy.plate.jacket", "heavy.plate.pants", "shoes.boots"), new[] { ExItem("lmg.m249", 1, 0) }) }; private static JObject ExRanges(float sense, float lose, float chase, float attack) => @@ -4225,10 +4233,19 @@ namespace Oxide.Plugins var known = new JArray(); foreach (JToken item in (JArray)kv.Value[list]) { - if (ItemManager.FindItemDefinition((string)item["Shortname"]) != null) - known.Add(item); - else + ItemDefinition def = ItemManager.FindItemDefinition((string)item["Shortname"]); + if (def == null) + { PrintWarning($"Example kit {kv.Key}: this Rust has no item '{item["Shortname"]}', so it is left out."); + continue; + } + + // D324: Kits sets an item's condition and maximum straight from the file, so each is + // written at this Rust's full durability for it (0 where the item has none). + float max = def.condition.enabled ? def.condition.max : 0f; + item["Condition"] = max; + item["MaxCondition"] = max; + known.Add(item); } kv.Value[list] = known; diff --git a/tools/RunicNpcTest.cs b/tools/RunicNpcTest.cs index 98e0800..1a7f52b 100644 --- a/tools/RunicNpcTest.cs +++ b/tools/RunicNpcTest.cs @@ -2423,6 +2423,18 @@ namespace Oxide.Plugins JObject items = kitFile?["_kits"]?["rnpc_juggernaut"] as JObject; int itemCount = items == null ? 0 : ((JArray)items["MainItems"]).Count + ((JArray)items["WearItems"]).Count + ((JArray)items["BeltItems"]).Count; Check("s6.examples.items", itemCount == 6, $"rnpc_juggernaut carries {itemCount} of its 6 items (a short name this Rust lacks would be left out)"); + // D324: every item is written at this Rust's full durability for it, 0 where it has none. + var worn = new List(); + foreach (string k in exampleKits) + foreach (string list in new[] { "MainItems", "WearItems", "BeltItems" }) + foreach (JToken it in (kitFile?["_kits"]?[k]?[list] as JArray) ?? new JArray()) + { + ItemDefinition def = ItemManager.FindItemDefinition((string)it["Shortname"]); + float want = def != null && def.condition.enabled ? def.condition.max : 0f; + if ((float)it["Condition"] != want || (float)it["MaxCondition"] != want) + worn.Add($"{k}/{it["Shortname"]} {it["Condition"]}/{it["MaxCondition"]} (want {want})"); + } + Check("s6.examples.fullCondition", worn.Count == 0, worn.Count == 0 ? "every item at its full durability" : string.Join("; ", worn.ToArray())); } // ---- stage 7: loot (D290–D301) ----