C#:
using Facepunch;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Oxide.Core;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using Oxide.Plugins.NpcSpawnExtensionMethods;
using ProtoBuf;
using Rust;
using Rust.Ai;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Reflection;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Networking;
using UnityEngine.UI;
namespace Oxide.Plugins {
[Info("NpcSpawn", "KpucTaJl", "3.2.9")]
internal class NpcSpawn : RustPlugin {
#region Config
private const bool En = false;
private PluginConfig Cfg {
get;
set;
}
protected override void LoadDefaultConfig() {
Puts("Creating a default config...");
Cfg = PluginConfig.DefaultConfig();
Cfg.PluginVersion = Version;
SaveConfig();
Puts("Creation of the default config completed!");
}
protected override void LoadConfig() {
base.LoadConfig();
Cfg = Config.ReadObject<PluginConfig>();
if (Cfg.GeneratePositionDelay < 0f) Cfg.GeneratePositionDelay = 0f;
if (Cfg.Weapons == null || Cfg.WeaponsParameters == null) {
PluginConfig defaultConfig = PluginConfig.DefaultConfig();
Cfg.Weapons ??= defaultConfig.Weapons;
Cfg.WeaponsParameters ??= defaultConfig.WeaponsParameters;
SaveConfig();
}
if (Cfg.PluginVersion < Version) UpdateConfigValues();
}
private void UpdateConfigValues() {
Puts("Config update detected! Updating config values...");
TryUpdateWeapons();
if (Cfg.PluginVersion < new VersionNumber(3, 2, 7)) {
PluginConfig defaultConfig = PluginConfig.DefaultConfig();
foreach (KeyValuePair<string, DefaultSettings> kvp in Cfg.WeaponsParameters) {
if (!defaultConfig.WeaponsParameters.TryGetValue(kvp.Key, out DefaultSettings settings)) continue;
kvp.Value.NpcDamageScale = settings.NpcDamageScale;
}
}
Cfg.PluginVersion = Version;
Puts("Config update completed!");
SaveConfig();
}
protected override void SaveConfig() => Config.WriteObject(Cfg);
private void TryUpdateWeapons() {
PluginConfig defaultConfig = PluginConfig.DefaultConfig();
foreach (KeyValuePair<string, DefaultSettings> kvp in defaultConfig.WeaponsParameters) if (!Cfg.WeaponsParameters.ContainsKey(kvp.Key)) Cfg.WeaponsParameters.Add(kvp.Key, kvp.Value);
foreach (KeyValuePair<int, HashSet<string>> kvp in defaultConfig.Weapons) {
foreach (string weapon in kvp.Value) {
if (Cfg.Weapons.Any(x => x.Value.Contains(weapon))) continue;
if (!Cfg.Weapons.TryGetValue(kvp.Key, out HashSet<string> weaponsMap)) {
weaponsMap = new HashSet<string>();
Cfg.Weapons.Add(kvp.Key, weaponsMap);
}
weaponsMap.Add(weapon);
}
}
}
public class DefaultSettings {
[JsonProperty(En ? "Effective Range" : "Дальность прицельной стрельбы")]
public float EffectiveRange {
get;
set;
}
[JsonProperty(En ? "Minimum Attack Duration" : "Минимальная продолжительность стрельбы")]
public float AttackLengthMin {
get;
set;
}
[JsonProperty(En ? "Maximum Attack Duration" : "Максимальная продолжительность стрельбы")]
public float AttackLengthMax {
get;
set;
}
[JsonProperty(En ? "Weapon Damage Multiplier" : "Множитель урона оружия")]
public float NpcDamageScale {
get;
set;
}
}
private class PluginConfig {
[JsonProperty(En ? "Delay after plugin startup before random positions are generated in biomes" : "Задержка после запуска плагина, по истечении которой будут генерироваться случайные позиции в биомах")]
public float GeneratePositionDelay {
get;
set;
}
[JsonProperty(En ? "Weapons with custom NPC parameters" : "Список оружия, у которого нет значений стандартных параметров для использования NPC")]
public Dictionary<string, DefaultSettings> WeaponsParameters {
get;
set;
}
[JsonProperty(En ? "NPC Weapons by Distance Category" : "Список оружия для использования NPC по категориям в зависимости от расстояния до цели")]
public Dictionary<int, HashSet<string>> Weapons {
get;
set;
}
[JsonProperty(En ? "Configuration version" : "Версия конфигурации")]
public VersionNumber PluginVersion {
get;
set;
}
public static PluginConfig DefaultConfig() {
return new PluginConfig {
GeneratePositionDelay = 5f, WeaponsParameters = new Dictionary<string, DefaultSettings> {
["rifle.bolt"]
= new DefaultSettings {
EffectiveRange = 150f, AttackLengthMin = -1f, AttackLengthMax = -1f, NpcDamageScale = 0.5f
}
, ["rifle.l96"] = new DefaultSettings {
EffectiveRange = 150f, AttackLengthMin = -1f, AttackLengthMax = -1f, NpcDamageScale = 0.5f
}
, ["multiplegrenadelauncher"] = new DefaultSettings {
EffectiveRange = 20f, AttackLengthMin = -1f, AttackLengthMax = -1f, NpcDamageScale = 0.5f
}
, ["smg.thompson"] = new DefaultSettings {
EffectiveRange = 20f, AttackLengthMin = 0.4f, AttackLengthMax = 0.4f, NpcDamageScale = 0.2f
}
, ["smg.2"] = new DefaultSettings {
EffectiveRange = 20f, AttackLengthMin = 0.4f, AttackLengthMax = 0.4f, NpcDamageScale = 0.25f
}
, ["t1_smg"] = new DefaultSettings {
EffectiveRange = 20f, AttackLengthMin = 0.4f, AttackLengthMax = 0.4f, NpcDamageScale = 0.4f
}
, ["blunderbuss"] = new DefaultSettings {
EffectiveRange = 15f, AttackLengthMin = 0.3f, AttackLengthMax = 1f, NpcDamageScale = 0.15f
}
, ["shotgun.double"] = new DefaultSettings {
EffectiveRange = 15f, AttackLengthMin = 0.3f, AttackLengthMax = 1f, NpcDamageScale = 0.15f
}
, ["shotgun.pump"] = new DefaultSettings {
EffectiveRange = 15f, AttackLengthMin = 0.3f, AttackLengthMax = 1f, NpcDamageScale = 0.15f
}
, ["shotgun.waterpipe"] = new DefaultSettings {
EffectiveRange = 15f, AttackLengthMin = -1f, AttackLengthMax = -1f, NpcDamageScale = 0.15f
}
, ["revolver.hc"] = new DefaultSettings {
EffectiveRange = 15f, AttackLengthMin = 0f, AttackLengthMax = 0.46f, NpcDamageScale = 0.18f
}
, ["pistol.python"] = new DefaultSettings {
EffectiveRange = 15f, AttackLengthMin = 0f, AttackLengthMax = 0.46f, NpcDamageScale = 0.21f
}
, ["pistol.prototype17"] = new DefaultSettings {
EffectiveRange = 15f, AttackLengthMin = 0f, AttackLengthMax = 0.46f, NpcDamageScale = 0.28f
}
, ["pistol.semiauto"] = new DefaultSettings {
EffectiveRange = 15f, AttackLengthMin = 0f, AttackLengthMax = 0.46f, NpcDamageScale = 0.28f
}
, ["speargun"] = new DefaultSettings {
EffectiveRange = 15f, AttackLengthMin = -1f, AttackLengthMax = -1f, NpcDamageScale = 0.25f
}
, ["bow.compound"] = new DefaultSettings {
EffectiveRange = 15f, AttackLengthMin = -1f, AttackLengthMax = -1f, NpcDamageScale = 0.25f
}
, ["crossbow"] = new DefaultSettings {
EffectiveRange = 15f, AttackLengthMin = -1f, AttackLengthMax = -1f, NpcDamageScale = 0.25f
}
, ["legacy bow"] = new DefaultSettings {
EffectiveRange = 15f, AttackLengthMin = -1f, AttackLengthMax = -1f, NpcDamageScale = 0.25f
}
, ["bow.hunting"] = new DefaultSettings {
EffectiveRange = 15f, AttackLengthMin = -1f, AttackLengthMax = -1f, NpcDamageScale = 0.25f
}
, ["minicrossbow"] = new DefaultSettings {
EffectiveRange = 15f, AttackLengthMin = -1f, AttackLengthMax = -1f, NpcDamageScale = 0.25f
}
, ["pistol.nailgun"] = new DefaultSettings {
EffectiveRange = 15f, AttackLengthMin = 0f, AttackLengthMax = 0.46f, NpcDamageScale = 0.25f
}
, ["blowpipe"] = new DefaultSettings {
EffectiveRange = 15f, AttackLengthMin = -1f, AttackLengthMax = -1f, NpcDamageScale = 0.25f
}
, ["pistol.eoka"] = new DefaultSettings {
EffectiveRange = 10f, AttackLengthMin = -1f, AttackLengthMax = -1f, NpcDamageScale = 0.25f
}
, ["snowballgun"] = new DefaultSettings {
EffectiveRange = 5f, AttackLengthMin = 2f, AttackLengthMax = 2f, NpcDamageScale = 0.2f
}
}
, Weapons = new Dictionary<int, HashSet<string>> {
[0]
= new HashSet<string> {
"bone.club", "knife.bone", "knife.butcher", "candycaneclub", "knife.combat", "longsword", "mace", "machete", "paddle", "pitchfork", "salvaged.cleaver", "salvaged.sword", "spear.stone", "spear.wooden", "chainsaw", "hatchet", "jackhammer", "pickaxe", "axe.salvaged", "hammer.salvaged", "icepick.salvaged", "stonehatchet", "stone.pickaxe", "torch", "sickle", "rock", "snowball", "mace.baseballbat", "concretepickaxe", "concretehatchet", "lumberjack.hatchet", "lumberjack.pickaxe", "diverhatchet", "diverpickaxe", "divertorch", "knife.skinning", "vampire.stake", "shovel", "spear.cny", "frontier_hatchet", "boomerang", "krieg.chainsword"
}
, [1] = new HashSet<string> {
"speargun", "bow.compound", "crossbow", "bow.hunting", "shotgun.double", "pistol.eoka", "flamethrower", "pistol.m92", "pistol.nailgun", "multiplegrenadelauncher", "shotgun.pump", "pistol.python", "pistol.revolver", "pistol.semiauto", "pistol.prototype17", "snowballgun", "shotgun.spas12", "shotgun.waterpipe", "shotgun.m4", "legacy bow", "military flamethrower", "blunderbuss", "minicrossbow", "blowpipe", "krieg.shotgun"
}
, [2] = new HashSet<string> {
"smg.2", "smg.mp5", "rifle.semiauto", "smg.thompson", "rifle.sks", "revolver.hc", "t1_smg"
}
, [3] = new HashSet<string> {
"rifle.ak", "rifle.lr300", "lmg.m249", "rifle.m39", "hmlmg", "rifle.ak.ice", "rifle.ak.diver", "minigun", "rifle.ak.med", "rifle.lr300.space"
}
, [4] = new HashSet<string> {
"rifle.bolt", "rifle.l96"
}
}
, PluginVersion = new VersionNumber()
}
;
}
}
#endregion Config
#region Data
private Dictionary<string, NpcConfig> Presets {
get;
set;
}
= new Dictionary<string, NpcConfig>();
private void LoadPresets() {
LoadFolder(string.Empty);
string path = Path.Combine(Interface.Oxide.DataFileSystem.Directory, "NpcSpawn/Preset/");
foreach (string name in Directory.GetDirectories(path)) {
string folderName = name.GetFolderName();
LoadFolder($"{folderName}/");
}
}
private void LoadFolder(string folderName) {
foreach (string name in Interface.Oxide.DataFileSystem.GetFiles($"NpcSpawn/Preset/{folderName}")) {
string fileName = name.GetFileName();
LoadFile(folderName, fileName);
}
}
private void LoadFile(string folderName, string fileName) {
NpcConfig config = Interface.Oxide.DataFileSystem.ReadObject<NpcConfig>($"NpcSpawn/Preset/{folderName}{fileName}");
if (config == null) {
PrintError($"File {fileName} is corrupted and cannot be loaded!");
return;
}
if (Presets.ContainsKey(fileName)) {
PrintError($"NPC preset with the name {fileName} already exists. The second preset with the same name cannot be loaded");
return;
}
config.UpdateValues();
config.UpdateStates();
Presets.Add(fileName, config);
SavePreset(fileName, config);
}
private NpcConfig TryLoadPreset(string preset) {
string folderName = GetFolderName(preset);
if (folderName == null) return null;
string path = string.IsNullOrEmpty(folderName) ? preset : folderName + "/" + preset;
NpcConfig config = config = Interface.Oxide.DataFileSystem.ReadObject<NpcConfig>($"NpcSpawn/Preset/{path}");
if (config == null) return null;
config.UpdateValues();
config.UpdateStates();
Presets.Add(preset, config);
return config;
}
private static void SavePreset(string preset, NpcConfig config) {
string folderName = GetFolderName(preset);
string path = string.IsNullOrEmpty(folderName) ? preset : folderName + "/" + preset;
Interface.Oxide.DataFileSystem.WriteObject($"NpcSpawn/Preset/{path}", config);
}
private static bool DataFileExists(string folder, string fileName) {
if (string.IsNullOrEmpty(fileName)) return false;
string path = string.IsNullOrEmpty(folder) ? fileName : folder + "/" + fileName;
return Interface.Oxide.DataFileSystem.ExistsDatafile($"NpcSpawn/Preset/{path}");
}
private static string GetFolderName(string preset) {
if (DataFileExists(string.Empty, preset)) return string.Empty;
string path = Path.Combine(Interface.Oxide.DataFileSystem.Directory, "NpcSpawn/Preset/");
foreach (string name in Directory.GetDirectories(path)) {
string folderName = name.GetFolderName();
if (DataFileExists(folderName, preset)) return folderName;
}
return null;
}
#endregion Data
#region NpcConfig
internal class NpcBelt {
public string ShortName {
get;
set;
}
public int Amount {
get;
set;
}
public ulong SkinID {
get;
set;
}
public HashSet<string> Mods {
get;
set;
}
public string Ammo {
get;
set;
}
}
internal class NpcWear {
public string ShortName {
get;
set;
}
public ulong SkinID {
get;
set;
}
}
internal class LootTableConfig {
public bool IsAlphaLoot {
get;
set;
}
public string AlphaLootPreset {
get;
set;
}
public bool IsLoottablePlugin {
get;
set;
}
public string LoottablePreset {
get;
set;
}
public bool IsCustomLootPlugin {
get;
set;
}
public string CustomLootPreset {
get;
set;
}
public bool ClearDefaultLoot {
get;
set;
}
public PrefabsLootTableConfig PrefabsTable {
get;
set;
}
public ItemsLootTableConfig ItemsTable {
get;
set;
}
public static LootTableConfig CreateDefault() {
return new LootTableConfig {
IsAlphaLoot = true, AlphaLootPreset = string.Empty, IsLoottablePlugin = true, LoottablePreset = string.Empty, IsCustomLootPlugin = true, CustomLootPreset = string.Empty, ClearDefaultLoot = false, PrefabsTable = PrefabsLootTableConfig.CreateDefault(), ItemsTable = ItemsLootTableConfig.CreateDefault()
}
;
}
public static LootTableConfig FromJObject(JObject obj) {
LootTableConfig cfg = CreateDefault();
cfg.IsAlphaLoot = obj.Read("IsAlphaLoot", cfg.IsAlphaLoot);
cfg.AlphaLootPreset = obj.Read("AlphaLootPreset", cfg.AlphaLootPreset);
cfg.IsLoottablePlugin = obj.Read("IsLoottablePlugin", cfg.IsLoottablePlugin);
cfg.LoottablePreset = obj.Read("LoottablePreset", cfg.LoottablePreset);
cfg.IsCustomLootPlugin = obj.Read("IsCustomLootPlugin", cfg.IsCustomLootPlugin);
cfg.CustomLootPreset = obj.Read("CustomLootPreset", cfg.CustomLootPreset);
cfg.ClearDefaultLoot = obj.Read("ClearDefaultLoot", cfg.ClearDefaultLoot);
if (obj.TryGetValue("PrefabsTable", out JToken prefabsTok) && prefabsTok is JObject prefabsObj) cfg.PrefabsTable = PrefabsLootTableConfig.FromJObject(prefabsObj);
if (obj.TryGetValue("ItemsTable", out JToken itemsTok) && itemsTok is JObject itemsObj) cfg.ItemsTable = ItemsLootTableConfig.FromJObject(itemsObj);
return cfg;
}
}
internal class ItemsLootTableConfig {
public bool IsEnabled {
get;
set;
}
public bool DisableMinMax {
get;
set;
}
public int MinItemsAmount {
get;
set;
}
public int MaxItemsAmount {
get;
set;
}
public List<LootItemConfig> Items {
get;
set;
}
public static ItemsLootTableConfig CreateDefault() {
return new ItemsLootTableConfig {
IsEnabled = false, DisableMinMax = true, MinItemsAmount = 1, MaxItemsAmount = 1, Items = null
}
;
}
public static ItemsLootTableConfig FromJObject(JObject obj) {
ItemsLootTableConfig cfg = CreateDefault();
cfg.IsEnabled = obj.Read("IsEnabled", cfg.IsEnabled);
cfg.DisableMinMax = obj.Read("DisableMinMax", cfg.DisableMinMax);
cfg.MinItemsAmount = obj.Read("MinItemsAmount", cfg.MinItemsAmount);
cfg.MaxItemsAmount = obj.Read("MaxItemsAmount", cfg.MaxItemsAmount);
if (obj.TryGetValue("Items", out JToken itemsTok) && itemsTok is JArray arr) {
List<LootItemConfig> list = new List<LootItemConfig>();
foreach (var t in arr) {
if (t is JObject itemObj) list.Add(LootItemConfig.FromJObject(itemObj));
}
cfg.Items = list.Count > 0 ? list : null;
}
return cfg;
}
}
internal class PrefabsLootTableConfig {
public bool IsEnabled {
get;
set;
}
public int MinPrefabsAmount {
get;
set;
}
public int MaxPrefabsAmount {
get;
set;
}
public List<LootPrefabConfig> Prefabs {
get;
set;
}
public static PrefabsLootTableConfig CreateDefault() {
return new PrefabsLootTableConfig {
IsEnabled = false, MinPrefabsAmount = 1, MaxPrefabsAmount = 1, Prefabs = null
}
;
}
public static PrefabsLootTableConfig FromJObject(JObject obj) {
PrefabsLootTableConfig cfg = CreateDefault();
cfg.IsEnabled = obj.Read("IsEnabled", cfg.IsEnabled);
cfg.MinPrefabsAmount = obj.Read("MinPrefabsAmount", cfg.MinPrefabsAmount);
cfg.MaxPrefabsAmount = obj.Read("MaxPrefabsAmount", cfg.MaxPrefabsAmount);
if (obj.TryGetValue("Prefabs", out JToken itemsTok) && itemsTok is JArray arr) {
List<LootPrefabConfig> list = new List<LootPrefabConfig>();
foreach (var t in arr) {
if (t is JObject itemObj) list.Add(LootPrefabConfig.FromJObject(itemObj));
}
cfg.Prefabs = list.Count > 0 ? list : null;
}
return cfg;
}
}
internal class LootItemConfig : LootElementChanceConfig {
public string Shortname {
get;
set;
}
public ulong Skin {
get;
set;
}
public string DisplayName {
get;
set;
}
public string OwnerName {
get;
set;
}
public bool IsBlueprint {
get;
set;
}
public static LootItemConfig CreateDefault() {
return new LootItemConfig {
Shortname = "scrap", Skin = 0, DisplayName = string.Empty, OwnerName = string.Empty, IsBlueprint = false, Chance = 100f, MinAmount = 1, MaxAmount = 1
}
;
}
public static LootItemConfig FromJObject(JObject obj) {
LootItemConfig cfg = CreateDefault();
cfg.Shortname = obj.Read("Shortname", cfg.Shortname);
cfg.Skin = obj.Read("Skin", cfg.Skin);
cfg.DisplayName = obj.Read("DisplayName", cfg.DisplayName);
cfg.OwnerName = obj.Read("OwnerName", cfg.OwnerName);
cfg.IsBlueprint = obj.Read("IsBlueprint", cfg.IsBlueprint);
cfg.Chance = obj.Read("Chance", cfg.Chance);
cfg.MinAmount = obj.Read("MinAmount", cfg.MinAmount);
cfg.MaxAmount = obj.Read("MaxAmount", cfg.MaxAmount);
return cfg;
}
}
internal class LootPrefabConfig : LootElementChanceConfig {
public string PrefabName {
get;
set;
}
public static LootPrefabConfig CreateDefault() {
return new LootPrefabConfig {
PrefabName = "assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_oilrig.prefab", Chance = 100f, MinAmount = 1, MaxAmount = 1
}
;
}
public static LootPrefabConfig FromJObject(JObject obj) {
LootPrefabConfig cfg = CreateDefault();
cfg.PrefabName = obj.Read("PrefabName", cfg.PrefabName);
cfg.Chance = obj.Read("Chance", cfg.Chance);
cfg.MinAmount = obj.Read("MinAmount", cfg.MinAmount);
cfg.MaxAmount = obj.Read("MaxAmount", cfg.MaxAmount);
return cfg;
}
}
internal class LootElementChanceConfig {
public float Chance {
get;
set;
}
public int MinAmount {
get;
set;
}
public int MaxAmount {
get;
set;
}
}
public class NpcConfig {
public string Prefab {
get;
set;
}
public string Names {
get;
set;
}
public int Gender {
get;
set;
}
public int SkinTone {
get;
set;
}
public uint Underwear {
get;
set;
}
public HashSet<NpcWear> WearItems {
get;
set;
}
public HashSet<NpcBelt> BeltItems {
get;
set;
}
public string Kit {
get;
set;
}
public bool DestroyTrapsOnDeath {
get;
set;
}
public float Health {
get;
set;
}
public bool InstantDeathIfHitHead {
get;
set;
}
public float RoamRange {
get;
set;
}
public float ChaseRange {
get;
set;
}
public float SenseRange {
get;
set;
}
public float ListenRange {
get;
set;
}
public float DamageRange {
get;
set;
}
public float ShortRange {
get;
set;
}
public float AttackLengthMaxShortRangeScale {
get;
set;
}
public float AttackRangeMultiplier {
get;
set;
}
public bool CheckVisionCone {
get;
set;
}
public float VisionCone {
get;
set;
}
public bool HostileTargetsOnly {
get;
set;
}
public bool DisplaySashTargetsOnly {
get;
set;
}
public bool IgnoreSafeZonePlayers {
get;
set;
}
public bool IgnoreSleepingPlayers {
get;
set;
}
public bool IgnoreWoundedPlayers {
get;
set;
}
public int NpcAttackMode {
get;
set;
}
public float NpcSenseRange {
get;
set;
}
public float NpcDamageScale {
get;
set;
}
public string NpcWhitelist {
get;
set;
}
public string NpcBlacklist {
get;
set;
}
public int AnimalAttackMode {
get;
set;
}
public float AnimalSenseRange {
get;
set;
}
public float AnimalDamageScale {
get;
set;
}
public string AnimalWhitelist {
get;
set;
}
public string AnimalBlacklist {
get;
set;
}
public float DamageScale {
get;
set;
}
public bool CanTurretTarget {
get;
set;
}
public float DamageScaleFromTurret {
get;
set;
}
public float DamageScaleToTurret {
get;
set;
}
public float AimConeScale {
get;
set;
}
public bool DisableRadio {
get;
set;
}
public bool CanRunAwayWater {
get;
set;
}
public bool CanSleep {
get;
set;
}
public float SleepDistance {
get;
set;
}
public float Speed {
get;
set;
}
public int AreaMask {
get;
set;
}
public int AgentTypeID {
get;
set;
}
public float BaseOffSet {
get;
set;
}
public string HomePosition {
get;
set;
}
public float MemoryDuration {
get;
set;
}
public HashSet<string> States {
get;
set;
}
public string LootPreset {
get;
set;
}
public LootTableConfig LootTable {
get;
set;
}
public string CratePrefab {
get;
set;
}
public bool IsRemoveCorpse {
get;
set;
}
public bool GroupAlertEnabled {
get;
set;
}
public float GroupAlertRadius {
get;
set;
}
public string GroupAlertReceivers {
get;
set;
}
public float HeadDamageScale {
get;
set;
}
public float BodyDamageScale {
get;
set;
}
public float LegDamageScale {
get;
set;
}
public float MeleeDamageScale {
get;
set;
}
public float BarricadeHealthThreshold {
get;
set;
}
public float BarricadeDistanceThreshold {
get;
set;
}
public float HealingScale {
get;
set;
}
public NpcConfig() {
}
public static NpcConfig CreateDefault() {
return new NpcConfig {
Prefab = "assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_heavy.prefab", Names = "Scientist", Gender = 0, SkinTone = 0, Underwear = 0, WearItems = new HashSet<NpcWear> {
new NpcWear {
ShortName = "hazmatsuit_scientist", SkinID = 0
}
}
, BeltItems = new HashSet<NpcBelt> {
new NpcBelt {
ShortName = "rifle.lr300", Amount = 1, SkinID = 0, Mods = new HashSet<string> {
"weapon.mod.lasersight", "weapon.mod.holosight"
}
, Ammo = string.Empty
}
, new NpcBelt {
ShortName = "smg.mp5", Amount = 1, SkinID = 0, Mods = new HashSet<string> {
"weapon.mod.flashlight"
}
, Ammo = string.Empty
}
, new NpcBelt {
ShortName = "pistol.m92", Amount = 1, SkinID = 0, Mods = new HashSet<string>(), Ammo = string.Empty
}
, new NpcBelt {
ShortName = "knife.combat", Amount = 1, SkinID = 0, Mods = new HashSet<string>(), Ammo = string.Empty
}
, new NpcBelt {
ShortName = "syringe.medical", Amount = 5, SkinID = 0, Mods = new HashSet<string>(), Ammo = string.Empty
}
, new NpcBelt {
ShortName = "grenade.f1", Amount = 5, SkinID = 0, Mods = new HashSet<string>(), Ammo = string.Empty
}
}
, Kit = string.Empty, DestroyTrapsOnDeath = false, Health = 100f, InstantDeathIfHitHead = false, RoamRange = 10f, ChaseRange = 80f, SenseRange = 40f, ListenRange = 20f, DamageRange = -1f, ShortRange = 10f, AttackLengthMaxShortRangeScale = 2f, AttackRangeMultiplier = 1f, CheckVisionCone = false, VisionCone = 286f, HostileTargetsOnly = false, DisplaySashTargetsOnly = false, IgnoreSafeZonePlayers = true, IgnoreSleepingPlayers = true, IgnoreWoundedPlayers = true, NpcAttackMode = 2, NpcSenseRange = 40f, NpcDamageScale = 1f, NpcWhitelist = "FrankensteinPet,14922524", NpcBlacklist = "11162132011012", AnimalAttackMode = 0, AnimalSenseRange = 20f, AnimalDamageScale = 1f, AnimalWhitelist = string.Empty, AnimalBlacklist = "11491311214163", DamageScale = 0.75f, MeleeDamageScale = 0.75f, CanTurretTarget = true, DamageScaleFromTurret = 0.5f, DamageScaleToTurret = 1f, AimConeScale = 2f, DisableRadio = false, CanRunAwayWater = true, CanSleep = false, SleepDistance = 100f, Speed = 5f, AreaMask = 1, AgentTypeID = -1372625422, BaseOffSet = 0f, HomePosition = string.Empty, MemoryDuration = 10f, States = new HashSet<string> {
"RoamState", "ChaseState", "CombatState"
}
, LootPreset = string.Empty, LootTable = LootTableConfig.CreateDefault(), CratePrefab = string.Empty, IsRemoveCorpse = false, GroupAlertEnabled = false, GroupAlertRadius = 40f, GroupAlertReceivers = string.Empty, HeadDamageScale = 1f, BodyDamageScale = 1f, LegDamageScale = 1f, BarricadeHealthThreshold = 30f, BarricadeDistanceThreshold = 12f, HealingScale = 1f
}
;
}
public void UpdateStates() {
if (States.Contains("RoamState") || States.Contains("ChaseState") || States.Contains("CombatState")) {
States.Clear();
States.Add("RoamState");
States.Add("ChaseState");
States.Add("CombatState");
}
else if (States.Contains("IdleState") || States.Contains("CombatStationaryState")) {
States.Clear();
States.Add("IdleState");
States.Add("CombatStationaryState");
}
}
public void UpdateValues() {
if (string.IsNullOrEmpty(Prefab)) Prefab = "assets/rust.ai/agents/npcplayer/humannpc/scientist/scientistnpc_heavy.prefab";
if (string.IsNullOrEmpty(Names)) Names = "Scientist";
if (Gender < 0) Gender = 0;
if (Gender > 2) Gender = 2;
if (SkinTone < 0) SkinTone = 0;
if (SkinTone > 4) SkinTone = 4;
if ((Underwear == 359039573 && Gender != 1) || (Underwear == 2059471831 && Gender != 2)) Underwear = 0;
States ??= new HashSet<string>();
if (States.Count == 0) States.Add("IdleState");
if (!States.Contains("IdleState") && !States.Contains("RoamState")) States.Add("IdleState");
WearItems ??= new HashSet<NpcWear>();
BeltItems ??= new HashSet<NpcBelt>();
Kit ??= string.Empty;
if (Health <= 0f) Health = 1f;
if (Speed < 0f) Speed = 0f;
if (RoamRange <= 2f) RoamRange = 0f;
if (RoamRange > ChaseRange) RoamRange = ChaseRange;
if (ChaseRange < 0f) ChaseRange = 0f;
if (SenseRange < 0f) SenseRange = 0f;
if (ListenRange < 0f) ListenRange = 0f;
if (DamageRange < -1f) DamageRange = -1f;
if (ShortRange < 0f) ShortRange = 0f;
if (AttackLengthMaxShortRangeScale < 1f) AttackLengthMaxShortRangeScale = 1f;
if (AttackRangeMultiplier < 0f) AttackRangeMultiplier = 0f;
if (VisionCone < 20f) VisionCone = 20f;
if (VisionCone > 340f) VisionCone = 340f;
if (DamageScale < 0f) DamageScale = 0f;
if (MeleeDamageScale <= 0f) MeleeDamageScale = DamageScale;
if (AimConeScale < 0f) AimConeScale = 0f;
if (DamageScaleFromTurret < 0f) DamageScaleFromTurret = 0f;
if (DamageScaleToTurret < 0f) DamageScaleToTurret = 0f;
if (CanTurretTarget && DamageScaleFromTurret == 0f && DamageScaleToTurret == 0f) CanTurretTarget = false;
if (SleepDistance < 0f) SleepDistance = 0f;
if (CanSleep && SleepDistance == 0f) CanSleep = false;
if (MemoryDuration < 1f) MemoryDuration = 1f;
if (AreaMask != 1 && AreaMask != 25) AreaMask = 1;
if (AgentTypeID != 0 && AgentTypeID != -1372625422) AgentTypeID = -1372625422;
if (NpcAttackMode < 0) NpcAttackMode = 0;
if (NpcAttackMode > 2) NpcAttackMode = 2;
if (AnimalAttackMode < 0) AnimalAttackMode = 0;
if (AnimalAttackMode > 2) AnimalAttackMode = 2;
if (NpcSenseRange < 0f) NpcSenseRange = 0f;
if (NpcSenseRange > SenseRange) NpcSenseRange = SenseRange;
if (AnimalSenseRange < 0f) AnimalSenseRange = 0f;
if (AnimalSenseRange > SenseRange) AnimalSenseRange = SenseRange;
if (NpcDamageScale < 0f) NpcDamageScale = 0f;
if (AnimalDamageScale < 0f) AnimalDamageScale = 0f;
NpcWhitelist ??= string.Empty;
AnimalWhitelist ??= string.Empty;
NpcBlacklist ??= string.Empty;
AnimalBlacklist ??= string.Empty;
LootPreset ??= string.Empty;
CratePrefab ??= string.Empty;
if (GroupAlertRadius < 0f) GroupAlertRadius = 0f;
if (GroupAlertEnabled && GroupAlertRadius == 0f) GroupAlertEnabled = false;
GroupAlertReceivers ??= string.Empty;
if (HeadDamageScale <= 0f) HeadDamageScale = 1f;
if (BodyDamageScale <= 0f) BodyDamageScale = 1f;
if (LegDamageScale <= 0f) LegDamageScale = 1f;
if (BarricadeHealthThreshold < 1f) BarricadeHealthThreshold = 30f;
if (BarricadeDistanceThreshold < 3f) BarricadeDistanceThreshold = 12f;
if (HealingScale <= 0f) HealingScale = 1f;
LootTable ??= LootTableConfig.CreateDefault();
LootTable.AlphaLootPreset ??= string.Empty;
LootTable.CustomLootPreset ??= string.Empty;
LootTable.LoottablePreset ??= string.Empty;
LootTable.PrefabsTable ??= PrefabsLootTableConfig.CreateDefault();
LootTable.ItemsTable ??= ItemsLootTableConfig.CreateDefault();
if (LootTable.PrefabsTable.Prefabs is {
Count : > 0
}
) {
foreach (LootPrefabConfig lootPrefabConfig in LootTable.PrefabsTable.Prefabs) {
lootPrefabConfig.PrefabName ??= string.Empty;
PrefabController.CachePrefab(lootPrefabConfig);
}
}
if (LootTable.ItemsTable.Items is {
Count : > 0
}
) {
foreach (LootItemConfig lootItemConfig in LootTable.ItemsTable.Items) {
lootItemConfig.Shortname ??= string.Empty;
lootItemConfig.DisplayName ??= string.Empty;
lootItemConfig.OwnerName ??= string.Empty;
}
}
}
public static NpcConfig FromJObject(JObject obj) {
NpcConfig cfg = CreateDefault();
cfg.Prefab = obj.Read("Prefab", cfg.Prefab);
cfg.Names = obj.Read("Names", "Name", cfg.Names);
cfg.Gender = obj.Read("Gender", cfg.Gender);
cfg.SkinTone = obj.Read("SkinTone", cfg.SkinTone);
cfg.Underwear = obj.Read("Underwear", cfg.Underwear);
cfg.Kit = obj.Read("Kit", cfg.Kit);
cfg.DestroyTrapsOnDeath = obj.Read("DestroyTrapsOnDeath", cfg.DestroyTrapsOnDeath);
cfg.Health = obj.Read("Health", cfg.Health);
cfg.InstantDeathIfHitHead = obj.Read("InstantDeathIfHitHead", cfg.InstantDeathIfHitHead);
cfg.RoamRange = obj.Read("RoamRange", cfg.RoamRange);
cfg.ChaseRange = obj.Read("ChaseRange", cfg.ChaseRange);
cfg.SenseRange = obj.Read("SenseRange", cfg.SenseRange);
cfg.ListenRange = obj.Read("ListenRange", cfg.ListenRange);
bool hasListenRange = obj.TryGetValue("ListenRange", out JToken tmp) && tmp != null && tmp.Type != JTokenType.Null && tmp.Type != JTokenType.Undefined;
bool hasSenseRange = obj.TryGetValue("SenseRange", out tmp) && tmp != null && tmp.Type != JTokenType.Null && tmp.Type != JTokenType.Undefined;
if (!hasListenRange && hasSenseRange) cfg.ListenRange = cfg.SenseRange / 2f;
cfg.DamageRange = obj.Read("DamageRange", cfg.DamageRange);
cfg.ShortRange = obj.Read("ShortRange", cfg.ShortRange);
cfg.AttackLengthMaxShortRangeScale = obj.Read("AttackLengthMaxShortRangeScale", cfg.AttackLengthMaxShortRangeScale);
cfg.AttackRangeMultiplier = obj.Read("AttackRangeMultiplier", cfg.AttackRangeMultiplier);
cfg.CheckVisionCone = obj.Read("CheckVisionCone", cfg.CheckVisionCone);
cfg.VisionCone = obj.Read("VisionCone", cfg.VisionCone);
cfg.HostileTargetsOnly = obj.Read("HostileTargetsOnly", cfg.HostileTargetsOnly);
cfg.DisplaySashTargetsOnly = obj.Read("DisplaySashTargetsOnly", cfg.DisplaySashTargetsOnly);
cfg.IgnoreSafeZonePlayers = obj.Read("IgnoreSafeZonePlayers", cfg.IgnoreSafeZonePlayers);
cfg.IgnoreSleepingPlayers = obj.Read("IgnoreSleepingPlayers", cfg.IgnoreSleepingPlayers);
cfg.IgnoreWoundedPlayers = obj.Read("IgnoreWoundedPlayers", cfg.IgnoreWoundedPlayers);
cfg.NpcAttackMode = obj.Read("NpcAttackMode", cfg.NpcAttackMode);
cfg.NpcSenseRange = obj.Read("NpcSenseRange", cfg.NpcSenseRange);
cfg.NpcDamageScale = obj.Read("NpcDamageScale", cfg.NpcDamageScale);
cfg.NpcWhitelist = obj.Read("NpcWhitelist", cfg.NpcWhitelist);
cfg.NpcBlacklist = obj.Read("NpcBlacklist", cfg.NpcBlacklist);
cfg.AnimalAttackMode = obj.Read("AnimalAttackMode", cfg.AnimalAttackMode);
cfg.AnimalSenseRange = obj.Read("AnimalSenseRange", cfg.AnimalSenseRange);
cfg.AnimalDamageScale = obj.Read("AnimalDamageScale", cfg.AnimalDamageScale);
cfg.AnimalWhitelist = obj.Read("AnimalWhitelist", cfg.AnimalWhitelist);
cfg.AnimalBlacklist = obj.Read("AnimalBlacklist", cfg.AnimalBlacklist);
cfg.DamageScale = obj.Read("DamageScale", cfg.DamageScale);
cfg.MeleeDamageScale = obj.Read("MeleeDamageScale", cfg.MeleeDamageScale);
bool hasMeleeDamageScale = obj.TryGetValue("MeleeDamageScale", out tmp) && tmp != null && tmp.Type != JTokenType.Null && tmp.Type != JTokenType.Undefined;
bool hasDamageScale = obj.TryGetValue("DamageScale", out tmp) && tmp != null && tmp.Type != JTokenType.Null && tmp.Type != JTokenType.Undefined;
if (!hasMeleeDamageScale && hasDamageScale) cfg.MeleeDamageScale = cfg.DamageScale;
cfg.CanTurretTarget = obj.Read("CanTurretTarget", cfg.CanTurretTarget);
cfg.DamageScaleFromTurret = obj.Read("DamageScaleFromTurret", "TurretDamageScale", cfg.DamageScaleFromTurret);
cfg.DamageScaleToTurret = obj.Read("DamageScaleToTurret", cfg.DamageScaleToTurret);
cfg.AimConeScale = obj.Read("AimConeScale", cfg.AimConeScale);
cfg.DisableRadio = obj.Read("DisableRadio", cfg.DisableRadio);
cfg.CanRunAwayWater = obj.Read("CanRunAwayWater", cfg.CanRunAwayWater);
cfg.CanSleep = obj.Read("CanSleep", cfg.CanSleep);
cfg.SleepDistance = obj.Read("SleepDistance", cfg.SleepDistance);
cfg.Speed = obj.Read("Speed", cfg.Speed);
cfg.AreaMask = obj.Read("AreaMask", cfg.AreaMask);
cfg.AgentTypeID = obj.Read("AgentTypeID", cfg.AgentTypeID);
cfg.BaseOffSet = obj.Read("BaseOffSet", cfg.BaseOffSet);
cfg.HomePosition = obj.Read("HomePosition", cfg.HomePosition);
cfg.MemoryDuration = obj.Read("MemoryDuration", cfg.MemoryDuration);
cfg.LootPreset = obj.Read("LootPreset", cfg.LootPreset);
cfg.CratePrefab = obj.Read("CratePrefab", cfg.CratePrefab);
cfg.IsRemoveCorpse = obj.Read("IsRemoveCorpse", cfg.IsRemoveCorpse);
cfg.GroupAlertEnabled
// ... [Code preview truncated due to length. Full source in attached file] ...