C#:
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Oxide.Core;
using Oxide.Core.Plugins;
using Rust;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
using Oxide.Plugins.BossMonsterExtensionMethods;
namespace Oxide.Plugins {
/*ПЛАГИН БЫЛ ПОФИКШЕН С ПОМОЩЬЮ ПРОГРАММЫ СКАЧАНОЙ С https://discord.gg/dNGbxafuJn */
[Info("BossMonster", "https://discord.gg/dNGbxafuJn", "2.1.0")]
internal class BossMonster : RustPlugin {
#region Config
private const bool En = false;
private PluginConfig _config;
protected override void LoadDefaultConfig() {
Puts("Creating a default config...");
_config = PluginConfig.DefaultConfig();
_config.PluginVersion = Version;
SaveConfig();
Puts("Creation of the default config completed!");
}
protected override void LoadConfig() {
base.LoadConfig();
_config = Config.ReadObject<PluginConfig>();
if (_config.PluginVersion < Version) UpdateConfigValues();
}
private void UpdateConfigValues() {
Puts("Config update detected! Updating config values...");
_config.PluginVersion = Version;
Puts("Config update completed!");
SaveConfig();
}
protected override void SaveConfig() => Config.WriteObject(_config);
public class GuiAnnouncementsConfig {
[JsonProperty(En ? "Do you use the GUI Announcements plugin? [true/false]" : "Использовать ли GUI Announcements? [true/false]")]
public bool IsGuiAnnouncements {
get;
set;
}
[JsonProperty(En ? "Banner color" : "Цвет баннера")]
public string BannerColor {
get;
set;
}
[JsonProperty(En ? "Text color" : "Цвет текста")]
public string TextColor {
get;
set;
}
[JsonProperty(En ? "Adjust Vertical Position" : "Отступ от верхнего края")]
public float ApiAdjustVPosition {
get;
set;
}
}
public class NotifyConfig {
[JsonProperty(En ? "Do you use the Notify plugin? [true/false]" : "Использовать ли плагин Notify? [true/false]")]
public bool IsNotify {
get;
set;
}
[JsonProperty(En ? "Type" : "Тип")]
public string Type {
get;
set;
}
}
public class DiscordConfig {
[JsonProperty(En ? "Do you use the Discord Messages plugin? [true/false]" : "Использовать ли плагин Discord Messages? [true/false]")]
public bool IsDiscord {
get;
set;
}
[JsonProperty("Webhook URL")]
public string WebhookUrl {
get;
set;
}
[JsonProperty(En ? "Embed Color (DECIMAL)" : "Цвет полосы (DECIMAL)")]
public int EmbedColor {
get;
set;
}
[JsonProperty(En ? "Keys of required messages" : "Ключи необходимых сообщений")]
public HashSet<string> Keys {
get;
set;
}
}
private class PluginConfig {
[JsonProperty(En ? "Prefix of chat messages" : "Префикс сообщений в чате")]
public string Prefix {
get;
set;
}
[JsonProperty(En ? "Do you use the chat? [true/false]" : "Использовать ли чат? [true/false]")]
public bool IsChat {
get;
set;
}
[JsonProperty(En ? "GUI Announcements setting" : "Настройка GUI Announcements")]
public GuiAnnouncementsConfig GuiAnnouncements {
get;
set;
}
[JsonProperty(En ? "Notify setting" : "Настройка Notify")]
public NotifyConfig Notify {
get;
set;
}
[JsonProperty(En ? "Discord setting (only for users DiscordMessages plugin)" : "Настройка оповещений в Discord (только для тех, кто использует плагин DiscordMessages)")]
public DiscordConfig Discord {
get;
set;
}
[JsonProperty(En ? "Use the PVE mode of the plugin? (only for users PveMode plugin)" : "Использовать PVE режим работы плагина? (только для тех, кто использует плагин PveMode)")]
public bool Pve {
get;
set;
}
[JsonProperty(En ? "NPC Turret Damage Multiplier" : "Множитель урона от турелей по NPC")]
public float TurretDamageScale {
get;
set;
}
[JsonProperty(En ? "Configuration version" : "Версия конфигурации")]
public VersionNumber PluginVersion {
get;
set;
}
public static PluginConfig DefaultConfig() {
return new PluginConfig() {
Prefix = "[BossMonster]", IsChat = true, GuiAnnouncements = new GuiAnnouncementsConfig {
IsGuiAnnouncements = false, BannerColor = "Orange", TextColor = "White", ApiAdjustVPosition = 0.03f
}
, Notify = new NotifyConfig {
IsNotify = false, Type = "0"
}
, Discord = new DiscordConfig {
IsDiscord = false, WebhookUrl = "https://support.discordapp.com/hc/en-us/articles/228383668-Intro-to-Webhooks", EmbedColor = 13516583, Keys = new HashSet<string> {
"Start", "Finish"
}
}
, Pve = false, TurretDamageScale = 0.5f, PluginVersion = new VersionNumber()
}
;
}
}
#endregion Config
#region Data
public class NpcWear {
[JsonProperty("ShortName")]
public string ShortName {
get;
set;
}
[JsonProperty("SkinID (0 - default)")]
public ulong SkinID {
get;
set;
}
}
public class NpcBelt {
[JsonProperty("ShortName")]
public string ShortName {
get;
set;
}
[JsonProperty(En ? "Amount" : "Кол-во")]
public int Amount {
get;
set;
}
[JsonProperty("SkinID (0 - default)")]
public ulong SkinID {
get;
set;
}
[JsonProperty(En ? "Mods" : "Модификации на оружие")]
public HashSet<string> Mods {
get;
set;
}
[JsonProperty(En ? "Ammo" : "Боеприпасы")]
public string Ammo {
get;
set;
}
}
public class ColorConfig {
[JsonProperty("r")]
public float R {
get;
set;
}
[JsonProperty("g")]
public float G {
get;
set;
}
[JsonProperty("b")]
public float B {
get;
set;
}
}
public class MarkerConfig {
[JsonProperty(En ? "Do you use the Marker? [true/false]" : "Использовать ли маркер? [true/false]")]
public bool IsMarker {
get;
set;
}
[JsonProperty(En ? "Radius" : "Радиус")]
public float Radius {
get;
set;
}
[JsonProperty(En ? "Transparency" : "Прозрачность")]
public float Alpha {
get;
set;
}
[JsonProperty(En ? "Marker color" : "Цвет маркера")]
public ColorConfig Color {
get;
set;
}
}
public class NpcEconomic {
[JsonProperty("Economics")]
public double Economics {
get;
set;
}
[JsonProperty(En ? "Server Rewards (minimum 1)" : "Server Rewards (минимум 1)")]
public int ServerRewards {
get;
set;
}
[JsonProperty(En ? "IQEconomic (minimum 1)" : "IQEconomic (минимум 1)")]
public int IQEconomic {
get;
set;
}
}
public class MonumentPositionsConfig {
[JsonProperty(En ? "Name of monument" : "Название монумента")]
public string Name {
get;
set;
}
[JsonProperty(En ? "List of positions" : "Список позиций")]
public HashSet<string> Positions {
get;
set;
}
}
public class ItemConfig {
[JsonProperty("ShortName")]
public string ShortName {
get;
set;
}
[JsonProperty(En ? "Minimum" : "Минимальное кол-во")]
public int MinAmount {
get;
set;
}
[JsonProperty(En ? "Maximum" : "Максимальное кол-во")]
public int MaxAmount {
get;
set;
}
[JsonProperty(En ? "Chance probability [0.0-100.0]" : "Шанс выпадения предмета [0.0-100.0]")]
public float Chance {
get;
set;
}
[JsonProperty(En ? "Is this a blueprint? [true/false]" : "Это чертеж? [true/false]")]
public bool IsBluePrint {
get;
set;
}
[JsonProperty("SkinID (0 - default)")]
public ulong SkinID {
get;
set;
}
[JsonProperty(En ? "Name (empty - default)" : "Название (empty - default)")]
public string Name {
get;
set;
}
}
public class LootTableConfig {
[JsonProperty(En ? "Minimum number of items" : "Минимальное кол-во элементов")]
public int Min {
get;
set;
}
[JsonProperty(En ? "Maximum number of items" : "Максимальное кол-во элементов")]
public int Max {
get;
set;
}
[JsonProperty(En ? "Use minimum and maximum values? [true/false]" : "Использовать минимальное и максимальное значение? [true/false]")]
public bool UseCount {
get;
set;
}
[JsonProperty(En ? "List of items" : "Список предметов")]
public List<ItemConfig> Items {
get;
set;
}
}
public class PrefabConfig {
[JsonProperty(En ? "Chance probability [0.0-100.0]" : "Шанс выпадения [0.0-100.0]")]
public float Chance {
get;
set;
}
[JsonProperty(En ? "The path to the prefab" : "Путь к prefab-у")]
public string PrefabDefinition {
get;
set;
}
}
public class PrefabLootTableConfig {
[JsonProperty(En ? "Minimum number of prefabs" : "Минимальное кол-во prefab-ов")]
public int Min {
get;
set;
}
[JsonProperty(En ? "Maximum number of prefabs" : "Максимальное кол-во prefab-ов")]
public int Max {
get;
set;
}
[JsonProperty(En ? "Use minimum and maximum values? [true/false]" : "Использовать минимальное и максимальное значение? [true/false]")]
public bool UseCount {
get;
set;
}
[JsonProperty(En ? "List of prefabs" : "Список prefab-ов")]
public List<PrefabConfig> Prefabs {
get;
set;
}
}
public class RadiusActionsConfig {
[JsonProperty(En ? "Use only one ability at a time? [true/false]" : "Одновременно использовать только одну способность? [true/false]")]
public bool UseOnlyOneAbility {
get;
set;
}
[JsonProperty(En ? "Radius (to disable all abilities, set the value to 0)" : "Радиус (чтобы отключить все способности установите значение 0)")]
public float Radius {
get;
set;
}
[JsonProperty(En ? "Spikes ability cooldown time (to disable the ability, set the value -1)" : "Время перезарядки способности Spikes (чтобы отключить способность установите значение -1)")]
public int TimeToSpikes {
get;
set;
}
[JsonProperty(En ? "Applied damage to player from Spikes" : "Получаемый урон игроком от Spikes")]
public float DamageSpikes {
get;
set;
}
[JsonProperty(En ? "FireBall ability cooldown time (to disable the ability, set the value -1)" : "Время перезарядки способности FireBall (чтобы отключить способность установите значение -1)")]
public int TimeToFire {
get;
set;
}
[JsonProperty(En ? "Applied damage to player from FireBall" : "Получаемый урон игроком от FireBall")]
public float DamageFire {
get;
set;
}
[JsonProperty(En ? "ElectricShock ability cooldown time (to disable the ability, set the value -1)" : "Время перезарядки способности ElectricShock (чтобы отключить способность установите значение -1)")]
public int TimeToElectricShock {
get;
set;
}
[JsonProperty(En ? "Applied damage to player from ElectricShock" : "Получаемый урон игроком от ElectricShock")]
public float DamageElectricShock {
get;
set;
}
[JsonProperty(En ? "Wounded ability cooldown time (to disable the ability, set the value -1)" : "Время перезарядки способности Wounded (чтобы отключить способность установите значение -1)")]
public int TimeToWounded {
get;
set;
}
[JsonProperty(En ? "Freeze ability cooldown time (to disable the ability, set the value -1)" : "Время перезарядки способности Freeze (чтобы отключить способность установите значение -1)")]
public int TimeToFreeze {
get;
set;
}
[JsonProperty(En ? "Animal Ability Settings" : "Настройки способности Animal")]
public AnimalAbility AnimalAbility {
get;
set;
}
[JsonProperty(En ? "NPC Ability Settings" : "Настройки способности NPC")]
public NpcAbility NpcAbility {
get;
set;
}
[JsonProperty(En ? "Radiation" : "Радиация")]
public float Radiation {
get;
set;
}
[JsonProperty(En ? "Temperature" : "Температура")]
public float Temperature {
get;
set;
}
}
public class AnimalAbility {
[JsonProperty(En ? "Ability Cooldown Time (to disable the ability, set the value -1)" : "Время перезарядки способности (чтобы отключить способность установите значение -1)")]
public int Time {
get;
set;
}
[JsonProperty(En ? "Type of animal (Wolf, Bear)" : "Тип животного (Wolf, Bear, Polar Bear)")]
public string Type {
get;
set;
}
[JsonProperty(En ? "Number of animals" : "Кол-во животных")]
public int Count {
get;
set;
}
[JsonProperty(En ? "Despawn time animals" : "Время удаления животных")]
public float DespawnTime {
get;
set;
}
}
public class NpcAbility {
[JsonProperty(En ? "Ability Cooldown Time (to disable the ability, set the value -1)" : "Время перезарядки способности (чтобы отключить способность установите значение -1)")]
public int Time {
get;
set;
}
[JsonProperty(En ? "NPC Settings" : "Настройки NPC")]
public AddNpcConfig ConfigNpc {
get;
set;
}
[JsonProperty(En ? "Number of NPCs" : "Кол-во NPC")]
public int Count {
get;
set;
}
[JsonProperty(En ? "Despawn time NPCs" : "Время удаления NPC")]
public float DespawnTime {
get;
set;
}
}
public class AddNpcConfig {
[JsonProperty(En ? "Names" : "Названия")]
public List<string> Names {
get;
set;
}
[JsonProperty(En ? "Health" : "Кол-во ХП")]
public float Health {
get;
set;
}
[JsonProperty(En ? "Roam Range" : "Дальность патрулирования местности")]
public float RoamRange {
get;
set;
}
[JsonProperty(En ? "Chase Range" : "Дальность погони за целью")]
public float ChaseRange {
get;
set;
}
[JsonProperty(En ? "Attack Range Multiplier" : "Множитель радиуса атаки")]
public float AttackRangeMultiplier {
get;
set;
}
[JsonProperty(En ? "Sense Range" : "Радиус обнаружения цели")]
public float SenseRange {
get;
set;
}
[JsonProperty(En ? "Target Memory Duration [sec.]" : "Длительность памяти цели [sec.]")]
public float MemoryDuration {
get;
set;
}
[JsonProperty(En ? "Scale damage" : "Множитель урона")]
public float DamageScale {
get;
set;
}
[JsonProperty(En ? "Aim Cone Scale" : "Множитель разброса")]
public float AimConeScale {
get;
set;
}
[JsonProperty(En ? "Detect the target only in the NPC's viewing vision cone? [true/false]" : "Обнаруживать цель только в углу обзора NPC? [true/false]")]
public bool CheckVisionCone {
get;
set;
}
[JsonProperty(En ? "Vision Cone" : "Угол обзора")]
public float VisionCone {
get;
set;
}
[JsonProperty(En ? "Speed" : "Скорость")]
public float Speed {
get;
set;
}
[JsonProperty(En ? "Disable radio effects? [true/false]" : "Отключать эффекты рации? [true/false]")]
public bool DisableRadio {
get;
set;
}
[JsonProperty(En ? "Wear items" : "Одежда")]
public HashSet<NpcWear> WearItems {
get;
set;
}
[JsonProperty(En ? "Belt items" : "Быстрые слоты")]
public HashSet<NpcBelt> BeltItems {
get;
set;
}
[JsonProperty(En ? "Kit (it is recommended to use the previous 2 settings to improve performance)" : "Kit (рекомендуется использовать предыдущие 2 пункта настройки для повышения производительности)")]
public string Kit {
get;
set;
}
}
public class TakeDamageActionsConfig {
[JsonProperty(En ? "Disable all abilities when applying damage? [true/false]" : "Отключить все способности при нанесении урона? [true/false]")]
public bool IsDisable {
get;
set;
}
[JsonProperty(En ? "Regeneration of health from the applied damage [%]" : "Восстановление здоровья от нанесенного урона [%]")]
public float Vampirism {
get;
set;
}
[JsonProperty(En ? "The amount of calories consumed" : "Кол-во калорий, которое расходуется")]
public float CaloriesTarget {
get;
set;
}
[JsonProperty(En ? "The amount of water consumed" : "Кол-во воды, которое расходуется")]
public float HydrationTarget {
get;
set;
}
[JsonProperty(En ? "The amount of added radiation" : "Кол-во добавляемой радиации")]
public float RadiationTarget {
get;
set;
}
[JsonProperty(En ? "The amount of added bleeding" : "Кол-во добавляемого кровотечения")]
public float BleedingTarget {
get;
set;
}
}
public class NpcConfig {
[JsonProperty(En ? "Name" : "Название")]
public string Name {
get;
set;
}
[JsonProperty(En ? "Health" : "Кол-во ХП")]
public float Health {
get;
set;
}
[JsonProperty(En ? "Roam Range" : "Дальность патрулирования местности")]
public float RoamRange {
get;
set;
}
[JsonProperty(En ? "Chase Range" : "Дальность погони за целью")]
public float ChaseRange {
get;
set;
}
[JsonProperty(En ? "Attack Range Multiplier" : "Множитель радиуса атаки")]
public float AttackRangeMultiplier {
get;
set;
}
[JsonProperty(En ? "Sense Range" : "Радиус обнаружения цели")]
public float SenseRange {
get;
set;
}
[JsonProperty(En ? "Target Memory Duration [sec.]" : "Длительность памяти цели [sec.]")]
public float MemoryDuration {
get;
set;
}
[JsonProperty(En ? "Scale damage" : "Множитель урона")]
public float DamageScale {
get;
set;
}
[JsonProperty(En ? "Aim Cone Scale" : "Множитель разброса")]
public float AimConeScale {
get;
set;
}
[JsonProperty(En ? "Detect the target only in the NPC's viewing vision cone? [true/false]" : "Обнаруживать цель только в углу обзора NPC? [true/false]")]
public bool CheckVisionCone {
get;
set;
}
[JsonProperty(En ? "Vision Cone" : "Угол обзора")]
public float VisionCone {
get;
set;
}
[JsonProperty(En ? "Speed" : "Скорость")]
public float Speed {
get;
set;
}
[JsonProperty(En ? "Minimum time of appearance after death [sec.]" : "Минимальное время появления после смерти [sec.]")]
public float MinTime {
get;
set;
}
[JsonProperty(En ? "Maximum time of appearance after death [sec.]" : "Максимальное время появления после смерти [sec.]")]
public float MaxTime {
get;
set;
}
[JsonProperty(En ? "Disable radio effects? [true/false]" : "Отключать эффекты рации? [true/false]")]
public bool DisableRadio {
get;
set;
}
[JsonProperty(En ? "Remove a corpse after death? (it is recommended to use the true value to improve performance) [true/false]" : "Удалять труп после смерти? (рекомендуется использовать значение true для повышения производительности) [true/false]")]
public bool IsRemoveCorpse {
get;
set;
}
[JsonProperty(En ? "Wear items" : "Одежда")]
public HashSet<NpcWear> WearItems {
get;
set;
}
[JsonProperty(En ? "Belt items" : "Быстрые слоты")]
public HashSet<NpcBelt> BeltItems {
get;
set;
}
[JsonProperty(En ? "Kit (it is recommended to use the previous 2 settings to improve performance)" : "Kit (рекомендуется использовать предыдущие 2 пункта настройки для повышения производительности)")]
public string Kit {
get;
set;
}
[JsonProperty(En ? "Marker settings" : "Настройки маркера")]
public MarkerConfig Marker {
get;
set;
}
[JsonProperty(En ? "The amount of economics that is given for killing the boss" : "Кол-во экономики, которое выдается за убийство босса")]
public NpcEconomic Economic {
get;
set;
}
[JsonProperty(En ? "List of monument locations" : "Список расположений на монументах")]
public HashSet<MonumentPositionsConfig> Monuments {
get;
set;
}
[JsonProperty(En ? "If the boss ends up below ocean sea level, should the boss return to it's place of appearance? [true/false]" : "Должен ли босс убегать на место своего появления, если он находится ниже уровня океана? [true/false]")]
public bool CanRunAwayWater {
get;
set;
}
[JsonProperty(En ? "Type of navigation grid (0 - used mainly on the island, 1 - used mainly under water or under land, as well as outside the map, can be used on some monuments)" : "Тип навигационной сетки (0 - используется в основном на острове, 1 - используется в основном под водой или землей, а также за пределами карты, может использоваться на некоторых монументах)")]
public int TypeNavMesh {
get;
set;
}
[JsonProperty(En ? "The distance at which you can apply damage to the boss (use 0 at any distance)" : "Дистанция, при которой можно наносить урон по боссу (при любой дистанции использовать 0)")]
public float PreventDamageRange {
get;
set;
}
[JsonProperty(En ? "Notify in a chat about actions with the boss? [true/false]" : "Оповещать в чате о действиях с боссом? [true/false]")]
public bool IsChat {
get;
set;
}
[JsonProperty(En ? "The path to the crate that appears at the place of death (empty - not used)" : "Путь к ящику, который появляется на месте смерти (empty - not used)")]
public string CratePrefab {
get;
set;
}
[JsonProperty(En ? "Which loot table should the plugin use? (0 - default; 1 - own; 2 - AlphaLoot; 3 - CustomLoot; 4 - loot table of the Rust objects; 5 - combine the 1 and 4 methods)" : "Какую таблицу предметов необходимо использовать? (0 - стандартную; 1 - собственную; 2 - AlphaLoot; 3 - CustomLoot; 4 - таблица предметов объектов Rust; 5 - совместить 1 и 4 методы)")]
public int TypeLootTable {
get;
set;
}
[JsonProperty(En ? "Loot table from prefabs (if the loot table type is 4 or 5)" : "Таблица предметов из prefab-ов (если тип таблицы предметов - 4 или 5)")]
public PrefabLootTableConfig PrefabLootTable {
get;
set;
}
[JsonProperty(En ? "Own loot table (if the loot table type is 1 or 5)" : "Собственная таблица предметов (если тип таблицы предметов - 1 или 5)")]
public LootTableConfig OwnLootTable {
get;
set;
}
[JsonProperty(En ? "All actions that occur with the player within the NPC radius" : "Все действия, которые происходят с игроком в радиусе NPC")]
public RadiusActionsConfig RadiusActions {
get;
set;
}
[JsonProperty(En ? "All actions that occur when applying NPC damage" : "Все действия, которые происходят при нанесении урона от NPC")]
public TakeDamageActionsConfig TakeDamageActions {
get;
set;
}
[JsonProperty(En ? "Use the invisibility ability? (use only for bosses with melee weapons) [true/false]" : "Использовать способность невидимости? (использовать только для боссов с оружием ближнего боя) [true/false]")]
public bool UseInvisible {
get;
set;
}
[JsonProperty(En ? "Enable damage to the boss with melee weapons only? [true/false]" : "Включить нанесение урона по боссу только оружием ближнего боя? [true/false]")]
public bool OnlyMeleeWeapon {
get;
set;
}
}
internal HashSet<NpcConfig> Configs = new HashSet<NpcConfig>();
private void LoadConfigs() {
Puts("Loading files on the /oxide/data/BossMonster/Bosses/ path has started...");
HashSet<string> allNamesForBosses = new HashSet<string>();
foreach (string name in Interface.Oxide.DataFileSystem.GetFiles("BossMonster/Bosses/")) {
string fileName = name.Split('/').Last().Split('.').First();
NpcConfig config = Interface.Oxide.DataFileSystem.ReadObject<NpcConfig>($"BossMonster/Bosses/{fileName}");
if (config != null) {
CheckLootTable(config.OwnLootTable);
CheckPrefabLootTable(config.PrefabLootTable);
if (allNamesForBosses.Contains(config.Name)) {
PrintWarning($"You can't use the same names for bosses! ({config.Name} -> {config.Name}|)");
config.Name += "|";
}
allNamesForBosses.Add(config.Name);
if (config.RoamRange > config.ChaseRange) {
config.RoamRange = config.ChaseRange;
PrintWarning($"Roam Range should not be higher than Chase Range! ({fileName})");
}
if (config.RadiusActions.AnimalAbility.Time != -1) {
if (config.RadiusActions.AnimalAbility.DespawnTime > config.RadiusActions.AnimalAbility.Time) {
config.RadiusActions.AnimalAbility.DespawnTime = config.RadiusActions.AnimalAbility.Time;
PrintWarning($"Despawn time animals should not be higher than Ability Cooldown Time! ({fileName})");
}
}
if (config.RadiusActions.NpcAbility.Time != -1) {
if (config.RadiusActions.NpcAbility.DespawnTime > config.RadiusActions.NpcAbility.Time) {
config.RadiusActions.NpcAbility.DespawnTime = config.RadiusActions.NpcAbility.Time;
PrintWarning($"Despawn time NPCs should not be higher than Ability Cooldown Time! ({fileName})");
}
if (config.RadiusActions.NpcAbility.ConfigNpc.RoamRange > config.RadiusActions.NpcAbility.ConfigNpc.ChaseRange) config.RadiusActions.NpcAbility.ConfigNpc.RoamRange = config.RadiusActions.NpcAbility.ConfigNpc.ChaseRange;
}
if (config.RadiusActions.TimeToFreeze == 0) config.RadiusActions.TimeToFreeze = -1;
if (config.RadiusActions.TimeToFire == 0) config.RadiusActions.TimeToFire = -1;
if (config.RadiusActions.TimeToElectricShock == 0) config.RadiusActions.TimeToElectricShock = -1;
if (config.RadiusActions.TimeToWounded == 0) config.RadiusActions.TimeToWounded = -1;
if (config.RadiusActions.TimeToFreeze == 0) config.RadiusActions.TimeToFreeze = -1;
if (config.RadiusActions.AnimalAbility.Time == 0) config.RadiusActions.AnimalAbility.Time = -1;
if (config.RadiusActions.NpcAbility.Time == 0) config.RadiusActions.NpcAbility.Time = -1;
Puts($"File {fileName} has been loaded successfully!");
Configs.Add(config);
Interface.Oxide.DataFileSystem.WriteObject($"BossMonster/Bosses/{fileName}", config);
}
else PrintError($"File {fileName} is corrupted and cannot be loaded!");
}
}
#endregion Data
#region Lang
protected override void LoadDefaultMessages() {
lang.RegisterMessages(new Dictionary<string, string> {
["Start"]
= "{0} <color=#55aaff>{1}</color> <color=#738d43>arrived</color> to zone <color=#55aaff>{2}</color>!", ["Finish"] = "{0} <color=#55aaff>{1}</color> killed <color=#55aaff>{2}</color> to zone <color=#55aaff>{3}</color>", ["NoDamage"] = "{0} You <color=#ce3f27>cannot</color> damage an boss from your position!", ["OnlyMeleeWeapon"] = "{0} You can only deal damage to this boss <color=#55aaff>with melee weapons</color>!"
}
, this);
lang.RegisterMessages(new Dictionary<string, string> {
["Start"]
= "{0} <color=#55aaff>{1}</color> <color=#738d43>прибыл</color> в квадрат <color=#55aaff>{2}</color>!", ["Finish"] = "{0} <color=#55aaff>{1}</color> убил <color=#55aaff>{2}</color> в квадрате <color=#55aaff>{3}</color>", ["NoDamage"] = "{0} Вы <color=#ce3f27>не можете</color> нанести урон боссу с текущей позиции!", ["OnlyMeleeWeapon"] = "{0} Вы <color=#738d43>можете</color> нанести урон по этому боссу <color=#55aaff>только оружием ближнего боя</color>!"
}
, this, "ru");
}
private string GetMessage(string langKey, string userID) => lang.GetMessage(langKey, _ins, userID);
private string GetMessage(string langKey, string userID, params object[] args) => (args.Length == 0) ? GetMessage(langKey, userID) : string.Format(GetMessage(langKey, userID), args);
#endregion Lang
#region Oxide Hooks
[PluginReference]
private readonly Plugin NpcSpawn, PveMode;
private static BossMonster _ins;
private void Init() => _ins = this;
private void OnServerInitialized() {
LoadDefaultMessages();
if (!plugins.Exists("NpcSpawn")) {
PrintError("NpcSpawn plugin doesn`t exist! Please read the file ReadMe.txt");
NextTick(() => Interface.Oxide.UnloadPlugin(Name));
return;
}
LoadConfigs();
LoadIDs();
LoadCustomMapPositions();
_monuments = TerrainMeta.Path.Monuments.Where(IsNecessaryMonument);
timer.In(10f, () => {
foreach (NpcConfig npcConfig in Configs) if (npcConfig.MinTime > 0f && npcConfig.MaxTime > 0f) SpawnBoss(npcConfig);
}
);
}
private void Unload() {
foreach (ControllerBoss controller in _controllers.Values) if (controller.Npc.IsExists()) controller.Npc.Kill();
_ins = null;
}
private void OnEntityTakeDamage(BasePlayer player, HitInfo info) {
if (!player.IsPlayer() || info == null) return;
ScientistNPC npc = info.Initiator as ScientistNPC;
if (npc == null) return;
ControllerBoss controller = null;
if (_controllers.TryGetValue(npc.net.ID.Value, out controller)) controller.TakeDamageActions(player, info);
}
private object OnEntityTakeDamage(ScientistNPC entity, HitInfo info) {
if (entity == null || info == null) return null;
if (_controllers.ContainsKey(entity.net.ID.Value)) {
BasePlayer attacker = info.InitiatorPlayer;
BaseEntity weaponPrefab = info.WeaponPrefab;
if (!attacker.IsPlayer()) return null;
if ((weaponPrefab == null || weaponPrefab.ShortPrefabName == "grenade.molotov.deployed" || weaponPrefab.ShortPrefabName == "rocket_fire") && info.damageTypes.GetMajorityDamageType() == Rust.DamageType.Heat) return true;
NpcConfig config = Configs.FirstOrDefault(x => x.Name == entity.displayName);
if (config.PreventDamageRange > 0f && Vector3.Distance(attacker.transform.position, entity.transform.position) > config.PreventDamageRange) {
AlertToPlayer(attacker, GetMessage("NoDamage", attacker.UserIDString, _config.Prefix));
return true;
}
if (config.OnlyMeleeWeapon) {
if (weaponPrefab == null || !(weaponPrefab is BaseMelee)) {
AlertToPlayer(attacker, GetMessage("OnlyMeleeWeapon", attacker.UserIDString, _config.Prefix));
return true;
}
if (weaponPrefab.ShortPrefabName == "jackhammer.entity" || weaponPrefab.ShortPrefabName == "chainsaw.entity") info.damageTypes.ScaleAll(0.25f);
}
}
return null;
}
private object OnEntityTakeDamage(BaseAnimalNPC animal, HitInfo info) {
if (animal == null || info == null) return null;
if (_controllers.Any(x => x.Value.Animals.Contains(animal))) {
if (info.InitiatorPlayer.IsPlayer()) return null;
else return true;
}
else return null;
}
private void OnEntityDeath(BasePlayer player, HitInfo info) {
if (!player.IsPlayer()) return;
ControllerBoss controller = _controllers.Values.FirstOrDefault(x => x.Players.Contains(player));
if (controller != null) controller.Players.Remove(player);
}
#endregion Oxide Hooks
#region Controller
private readonly Dictionary<ulong, ControllerBoss> _controllers = new Dictionary<ulong, ControllerBoss>();
private void SpawnBoss(NpcConfig config) {
Vector3 pos = GetSpawnPos(config);
if (pos == Vector3.zero) {
timer.In(UnityEngine.Random.Range(config.MinTime, config.MaxTime), () => SpawnBoss(config));
return;
}
ScientistNPC npc = (ScientistNPC)NpcSpawn.Call("SpawnNpc", pos, GetObjectConfig(config));
if (npc == null) {
PrintError($"{config.Name} spawn error!");
return;
}
ControllerBoss controller = npc.gameObject.AddComponent<ControllerBoss>();
controller.InitData(config);
_controllers.Add(npc.net.ID.Value, controller);
if (_config.Pve && plugins.Exists("PveMode")) PveMode.Call("ScientistAddPveMode", npc);
if (config.IsChat) AlertToAllPlayers("Start", _config.Prefix, config.Name, MapHelper.PositionToString(npc.transform.position));
Interface.Oxide.CallHook("OnBossSpawn", npc);
}
private JObject GetObjectConfig(NpcConfig config) {
HashSet<string> states = new HashSet<string> {
"RoamState", "ChaseState", "CombatState"
}
;
if (config.BeltItems.Any(x => x.ShortName == "rocket.launcher" || x.ShortName == "explosive.timed")) states.Add("RaidState");
return new JObject {
["Name"]
= config.Name, ["WearItems"] = new JArray {
config.WearItems.Select(x => new JObject {
["ShortName"]
= x.ShortName, ["SkinID"] = x.SkinID
}
)
}
, ["BeltItems"] = new JArray {
config.BeltItems.Select(x => new JObject {
["ShortName"]
= x.ShortName, ["Amount"] = x.Amount, ["SkinID"] = x.SkinID, ["Mods"] = new JArray {
x.Mods
}
, ["Ammo"] = x.Ammo
}
)
}
, ["Kit"] = config.Kit, ["Health"] = config.Health, ["RoamRange"] = config.RoamRange, ["ChaseRange"] = config.ChaseRange, ["SenseRange"] = config.SenseRange, ["ListenRange"] = config.SenseRange / 2f, ["AttackRangeMultiplier"] = config.AttackRangeMultiplier, ["CheckVisionCone"] = config.CheckVisionCone, ["VisionCone"] = config.VisionCone, ["DamageScale"] = config.DamageScale, ["TurretDamageScale"] = _config.TurretDamageScale, ["AimConeScale"] = config.AimConeScale, ["DisableRadio"] = config.DisableRadio, ["CanRunAwayWater"] = config.CanRunAwayWater, ["CanSleep"] = false, ["Speed"] = config.Speed, ["AreaMask"] = config.TypeNavMesh == 0 ? 1 : 25, ["AgentTypeID"] = config.TypeNavMesh == 0 ? -1372625422 : 0, ["HomePosition"] = string.Empty, ["MemoryDuration"] = config.MemoryDuration, ["States"] = new JArray {
states
}
}
;
}
internal class ControllerBoss : FacepunchBehaviour {
internal ScientistNPC Npc;
private MapMarkerGenericRadius _mapmarker;
private VendingMachineMapMarker _vendingMarker;
private float _maxHealth;
private bool _сanRunAwayWater;
private int _typeNavMesh;
internal RadiusActionsConfig radiusActions = null;
private readonly GameObject _customSphere = new GameObject();
private int _timeToSpikes = -1;
private int _timeToFire = -1;
private int _timeToElectricShock = -1;
private int _timeToWounded = -1;
private int _timeToFreeze = -1;
private int _timeToAnimal = -1;
private int _timeToNpc = -1;
private readonly HashSet<Barricade> _allSpikes = new HashSet<Barricade>();
private Coroutine _fireBallCoroutine = null;
private Coroutine _electricShockCoroutine = null;
private readonly HashSet<BasePlayer> _woundedPlayers = new HashSet<BasePlayer>();
private Coroutine _freezeCoroutine = null;
private readonly HashSet<IceFence> _allWalls = new HashSet<IceFence>();
private readonly Dictionary<BasePlayer, Vector3> _freezePlayers = new Dictionary<BasePlayer, Vector3>();
internal HashSet<BaseAnimalNPC> Animals = new HashSet<BaseAnimalNPC>();
internal HashSet<ScientistNPC> Scientists = new HashSet<ScientistNPC>();
private TakeDamageActionsConfig _takeDamageActions = null;
internal HashSet<BasePlayer> Players = new HashSet<BasePlayer>();
private Vector3 _homePosition;
private int _timeToInvis = 5;
private int _timeToGoHome = 0;
private int _timeToGhost = 3;
private void Awake() {
Npc = GetComponent<ScientistNPC>();
}
internal void InitData(NpcConfig config) {
if (config.Marker.IsMarker) SpawnMapMarker(config.Marker);
_maxHealth = config.Health;
_сanRunAwayWater = config.CanRunAwayWater;
_typeNavMesh = config.TypeNavMesh;
if (config.RadiusActions.Radius > 0f) {
radiusActions = config.RadiusActions;
_customSphere.AddComponent<CustomSphereCollider>().InitData(this);
_timeToSpikes = radiusActions.TimeToSpikes;
_timeToFire = radiusActions.TimeToFire;
_timeToElectricShock = radiusActions.TimeToElectricShock;
_timeToWounded = radiusActions.TimeToWounded;
_timeToFreeze = radiusActions.TimeToFreeze;
_timeToAnimal = radiusActions.AnimalAbility.Time;
_timeToNpc = radiusActions.NpcAbility.Time;
if (radiusActions.Radiation > 0f) InitRadiation(radiusActions.Radiation);
if (radiusActions.Temperature != 0f) InitTemperature(radiusActions.Temperature);
InvokeRepeating(RadiusActions, 1f, 1f);
}
if (!config.TakeDamageActions.IsDisable) _takeDamageActions = config.TakeDamageActions;
_homePosition = Npc.transform.position;
if (config.UseInvisible) InvokeRepeating(CheckInvisible, 1f, 1f);
}
private void OnDestroy() {
CancelInvoke(UpdateMapMarker);
if (_mapmarker.IsExists()) _mapmarker.Kill();
if (_vendingMarker.IsExists()) _vendingMarker.Kill();
CancelInvoke(RadiusActions);
if (_customSphere != null) Destroy(_customSphere);
CancelInvoke(DeleteAllSpikes);
DeleteAllSpikes();
if (_fireBallCoroutine != null) ServerMgr.Instance.StopCoroutine(_fireBallCoroutine);
if (_electricShockCoroutine != null) ServerMgr.Instance.StopCoroutine(_electricShockCoroutine);
CancelInvoke(FinishWounded);
FinishWounded();
if (_freezeCoroutine != null) ServerMgr.Instance.StopCoroutine(_freezeCoroutine);
DeleteAllWalls();
CancelInvoke(DeleteAllAnimals);
DeleteAllAnimals();
CancelInvoke(DeleteAllScientists);
DeleteAllScientists();
CancelInvoke(CheckInvisible);
}
private void SpawnMapMarker(MarkerConfig config) {
_mapmarker = GameManager.server.CreateEntity("assets/prefabs/tools/map/genericradiusmarker.prefab", transform.position) as MapMarkerGenericRadius;
_mapmarker.Spawn();
// ... [Code preview truncated due to length. Full source in attached file] ...