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;
///Скачано с дискорд сервера Rust Edit [PRO+]
///discord.gg/9vyTXsJyKR
namespace Oxide.Plugins {
[Info("BossMonster", "discord.gg/9vyTXsJyKR", "2.0.4")]
internal class BossMonster : RustPlugin {
#region Config
private const bool En = true;
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 ? "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 ? "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 ? "Should I apply the boss behavior to a place that is below ocean level? [true/false]" : "Применить ли поведение босса для места, которое находится ниже уровня океана? [true/false]")]
public bool IsBelowOceanLevel {
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;
}
}
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;
}
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!"
}
, 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> нанести урон боссу с текущей позиции!"
}
, 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) 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, 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)) {
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;
}
}
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<uint, ControllerBoss> _controllers = new Dictionary<uint, 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, controller);
if (_config.Pve && plugins.Exists("PveMode")) PveMode.Call("ScientistAddPveMode", npc);
if (config.IsChat) AlertToAllPlayers("Start", _config.Prefix, config.Name, PhoneController.PositionToGridCoord(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, ["DamageScale"] = config.DamageScale, ["TurretDamageScale"] = _config.TurretDamageScale, ["AimConeScale"] = config.AimConeScale, ["DisableRadio"] = config.DisableRadio, ["CanUseWeaponMounted"] = true, ["CanRunAwayWater"] = !config.IsBelowOceanLevel, ["Speed"] = config.Speed, ["AreaMask"] = config.IsBelowOceanLevel ? 25 : 1, ["AgentTypeID"] = config.IsBelowOceanLevel ? 0 : -1372625422, ["HomePosition"] = string.Empty, ["States"] = new JArray {
states
}
, ["Sensory"] = new JObject {
["AttackRangeMultiplier"]
= config.AttackRangeMultiplier, ["SenseRange"] = config.SenseRange, ["MemoryDuration"] = config.MemoryDuration, ["CheckVisionCone"] = config.CheckVisionCone, ["VisionCone"] = config.VisionCone
}
}
;
}
internal class ControllerBoss : FacepunchBehaviour {
internal ScientistNPC Npc;
private MapMarkerGenericRadius _mapmarker;
private VendingMachineMapMarker _vendingMarker;
private float _maxHealth;
private bool _isBelowOceanLevel;
internal RadiusActionsConfig radiusActions = null;
private GameObject _customSphere = new GameObject();
private int _timeToSpikes = -1;
private int _timeToFire = -1;
private int _timeToElectricShock = -1;
private int _timeToWounded = -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>();
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;
_isBelowOceanLevel = config.IsBelowOceanLevel;
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;
_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();
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();
_mapmarker.radius = config.Radius;
_mapmarker.alpha = config.Alpha;
_mapmarker.color1 = new Color(config.Color.R, config.Color.G, config.Color.B);
_vendingMarker = GameManager.server.CreateEntity("assets/prefabs/deployable/vendingmachine/vending_mapmarker.prefab", transform.position) as VendingMachineMapMarker;
_vendingMarker.Spawn();
_vendingMarker.markerShopName = $"{Npc.displayName} ({(int)Npc.health} HP)";
InvokeRepeating(UpdateMapMarker, 0, 1f);
}
private void UpdateMapMarker() {
_mapmarker.transform.position = transform.position;
_mapmarker.SendUpdate();
_mapmarker.SendNetworkUpdate();
_vendingMarker.transform.position = transform.position;
_vendingMarker.markerShopName = $"{Npc.displayName} ({(int)Npc.health} HP)";
_vendingMarker.SendNetworkUpdate();
}
private void InitRadiation(float value) {
TriggerRadiation trigger = _customSphere.AddComponent<TriggerRadiation>();
trigger.RadiationAmountOverride = value;
trigger.interestLayers = 1 << 17;
}
private void InitTemperature(float value) {
TriggerTemperature trigger = _customSphere.AddComponent<TriggerTemperature>();
trigger.Temperature = value;
trigger.triggerSize = radiusActions.Radius;
trigger.interestLayers = 1 << 17;
}
private void RadiusActions() {
if (_timeToSpikes > 0) _timeToSpikes--;
if (_timeToFire > 0) _timeToFire--;
if (_timeToElectricShock > 0) _timeToElectricShock--;
if (_timeToAnimal > 0) _timeToAnimal--;
if (_timeToWounded > 0) _timeToWounded--;
if (_timeToNpc > 0) _timeToNpc--;
if (Players.Count == 0) return;
if (_timeToSpikes == 0) {
_timeToSpikes = radiusActions.TimeToSpikes;
foreach (BasePlayer player in Players.ToList()) {
Barricade spikes = GameManager.server.CreateEntity("assets/prefabs/deployable/floor spikes/spikes.floor.prefab", player.transform.position, player.transform.rotation) as Barricade;
spikes.enableSaving = false;
spikes.Spawn();
foreach (Collider collider in spikes.GetComponentsInChildren<Collider>()) DestroyImmediate(collider);
player.Hurt(radiusActions.DamageSpikes, DamageType.Stab, Npc, false);
_allSpikes.Add(spikes);
Invoke(DeleteAllSpikes, 5f);
}
if (radiusActions.UseOnlyOneAbility) return;
}
if (_timeToFire == 0) {
_timeToFire = radiusActions.TimeToFire;
_fireBallCoroutine = ServerMgr.Instance.StartCoroutine(AbilityFireBall());
if (radiusActions.UseOnlyOn
// ... [Code preview truncated due to length. Full source in attached file] ...