C#:
using Facepunch;
using Newtonsoft.Json;
using Oxide.Core.Plugins;
using Rust;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace Oxide.Plugins {
[Info("ChinookIvent", "TopPlugin.ru", "1.0.1")]
public class ChinookIvent : RustPlugin {
#region
private new void LoadDefaultMessages() {
lang.RegisterMessages(new Dictionary<string, string> {
["ChinookBuild"]
= "<color=#E66062>Вы не можете строить в зоне ивента</color>", ["ChinookStart"] = "<color=#608FE6>Чинук с особым грузом</color> уже вылител на место сброса.\nКвадрат сброса <color=#6ACB52>{0}</color>", ["ChinookIsDead"] = "<color=#608FE6>Чинук с особым грузом</color> потерпел крушения!!!", ["ChinookFinish"] = "<color=#608FE6>Чинук с особым грузом</color> прилител на место сброса (квадрат <color=#6ACB52>{0}</color>), осталось подождать <color=#3DA9FF>{1}</color> \n Метка на карте G", ["ChinookIsDrop"] = "<color=#608FE6>Чинук с особым грузом</color> сбросил очень ценный груз (квадрат <color=#6ACB52>{0}</color>)\n Метка на карте G", ["ChinookIsDropHack"] = "<color=#FFAB3D>Особый груз кто то начал взламывать!</color>\nУ тебя есть 15 минут до его открытие\nКвадрат (<color=#6ACB52>{0}</color>) Метка на карте G", ["ChinookIsDropHackEnd"] = "<color=#FFAB3D>Особый груз взломан но не залутан!</color>", ["ChinookIsDropHackEndLoot"] = "Особый груз залутан игроком <color=#6ACB52>{0}</color>.",
}
, this);
lang.RegisterMessages(new Dictionary<string, string> {
["ChinookBuild"]
= "<color=#E66062>Вы не можете строить в зоне ивента</color>", ["ChinookStart"] = "<color=#608FE6>Чинук с особым грузом</color> уже вылител на место сброса.\nКвадрат сброса <color=#6ACB52>{0}</color>", ["ChinookIsDead"] = "<color=#608FE6>Чинук с особым грузом</color> потерпел крушения!!!", ["ChinookFinish"] = "<color=#608FE6>Чинук с особым грузом</color> прилител на место сброса (квадрат <color=#6ACB52>{0}</color>), осталось подождать <color=#3DA9FF>{1}</color> \n Метка на карте G", ["ChinookIsDrop"] = "<color=#608FE6>Чинук с особым грузом</color> сбросил очень ценный груз (квадрат <color=#6ACB52>{0}</color>)\n Метка на карте G", ["ChinookIsDropHack"] = "<color=#FFAB3D>Особый груз кто то начал взламывать!</color>\nУ тебя есть 15 минут до его открытие\nКвадрат (<color=#6ACB52>{0}</color>) Метка на карте G", ["ChinookIsDropHackEnd"] = "<color=#FFAB3D>Особый груз взломан но не залутан!</color>", ["ChinookIsDropHackEndLoot"] = "Особый груз залутан игроком <color=#6ACB52>{0}</color>.",
}
, this, "ru");
}
#endregion
#region Config
public Configurarion config;
public class ItemsDrop {
[JsonProperty("Short name")]
public string Shortname;
[JsonProperty("Skin ID ")]
public ulong SkinID;
[JsonProperty("Имя предмета")]
public string DisplayName;
[JsonProperty("Чертеж?")]
public bool BluePrint;
[JsonProperty("Мин кол")]
public int MinimalAmount = 0;
[JsonProperty("макс кол")]
public int MaximumAmount = 0;
[JsonProperty("Шанс выпадения предмета")]
public int DropChance = 0;
}
public class ChinookSetings {
[JsonProperty("Время ожидания сброса")]
public int TimeStamp = 0;
[JsonProperty("Минимальное колличевство игроков для запуска ивента")]
public int PlayersMin = 20;
[JsonProperty("Раз в сколько часов будет летать чинук")]
public int TimeChinook = 7200;
[JsonProperty("Максимум предметов в 1 ящике")]
public int MaxItem = 7;
[JsonProperty("Выпадаемые предметы")]
public List<ItemsDrop> itemsDrops;
}
public class Configurarion {
[JsonProperty("Настройки")]
public ChinookSetings chinook;
}
protected override void LoadDefaultConfig() {
config = new Configurarion() {
chinook = new ChinookSetings {
itemsDrops = new List<ItemsDrop> {
new ItemsDrop {
Shortname = "halloween.surgeonsuit", SkinID = 0, DisplayName = "", BluePrint = false, MinimalAmount = 1, MaximumAmount = 1, DropChance = 70
}
, new ItemsDrop {
Shortname = "halloween.surgeonsuit", SkinID = 0, DisplayName = "", BluePrint = false, MinimalAmount = 1, MaximumAmount = 1, DropChance = 70
}
, new ItemsDrop {
Shortname = "halloween.surgeonsuit", SkinID = 0, DisplayName = "", BluePrint = false, MinimalAmount = 1, MaximumAmount = 1, DropChance = 70
}
, new ItemsDrop {
Shortname = "halloween.surgeonsuit", SkinID = 0, DisplayName = "", BluePrint = false, MinimalAmount = 1, MaximumAmount = 1, DropChance = 70
}
, new ItemsDrop {
Shortname = "halloween.surgeonsuit", SkinID = 0, DisplayName = "", BluePrint = false, MinimalAmount = 1, MaximumAmount = 1, DropChance = 70
}
, new ItemsDrop {
Shortname = "halloween.surgeonsuit", SkinID = 0, DisplayName = "", BluePrint = false, MinimalAmount = 1, MaximumAmount = 1, DropChance = 70
}
, new ItemsDrop {
Shortname = "halloween.surgeonsuit", SkinID = 0, DisplayName = "", BluePrint = false, MinimalAmount = 1, MaximumAmount = 1, DropChance = 70
}
, new ItemsDrop {
Shortname = "halloween.surgeonsuit", SkinID = 0, DisplayName = "", BluePrint = false, MinimalAmount = 1, MaximumAmount = 1, DropChance = 70
}
, new ItemsDrop {
Shortname = "metal.facemask", SkinID = 1886184322, DisplayName = "", BluePrint = false, MinimalAmount = 1, MaximumAmount = 1, DropChance = 20
}
, new ItemsDrop {
Shortname = "door.double.hinged.metal", SkinID = 1911015010, DisplayName = "", BluePrint = false, MinimalAmount = 1, MaximumAmount = 2, DropChance = 60
}
, new ItemsDrop {
Shortname = "rifle.bolt", SkinID = 0, DisplayName = "", BluePrint = true, MinimalAmount = 1, MaximumAmount = 1, DropChance = 10
}
, new ItemsDrop {
Shortname = "rifle.lr300", SkinID = 0, DisplayName = "", BluePrint = false, MinimalAmount = 1, MaximumAmount = 1, DropChance = 15
}
, new ItemsDrop {
Shortname = "pistol.revolver", SkinID = 0, DisplayName = "", BluePrint = false, MinimalAmount = 1, MaximumAmount = 3, DropChance = 60
}
, new ItemsDrop {
Shortname = "supply.signal", SkinID = 0, DisplayName = "", BluePrint = false, MinimalAmount = 1, MaximumAmount = 3, DropChance = 20
}
, new ItemsDrop {
Shortname = "explosive.satchel", SkinID = 0, DisplayName = "", BluePrint = false, MinimalAmount = 1, MaximumAmount = 3, DropChance = 5
}
, new ItemsDrop {
Shortname = "grenade.smoke", SkinID = 0, DisplayName = "", BluePrint = false, MinimalAmount = 1, MaximumAmount = 20, DropChance = 45
}
, new ItemsDrop {
Shortname = "ammo.rifle", SkinID = 0, DisplayName = "", BluePrint = false, MinimalAmount = 50, MaximumAmount = 120, DropChance = 35
}
, new ItemsDrop {
Shortname = "scrap", SkinID = 0, DisplayName = "", BluePrint = false, MinimalAmount = 100, MaximumAmount = 500, DropChance = 20
}
, new ItemsDrop {
Shortname = "giantcandycanedecor", SkinID = 0, DisplayName = "Новый год", BluePrint = false, MinimalAmount = 1, MaximumAmount = 5, DropChance = 70
}
,
}
}
}
;
SaveConfig(config);
}
void SaveConfig(Configurarion config) {
Config.WriteObject(config, true);
SaveConfig();
}
public void LoadConfigVars() {
config = Config.ReadObject<Configurarion>();
Config.WriteObject(config, true);
}
#endregion
[ChatCommand("goch")]
private void ChinookCall(BasePlayer player) {
if (!player.IsAdmin) return;
ChinookHelicopterCall();
}
#region Метка на g карте
private void CreateMarker(Vector3 position, float refreshRate, string name, string displayName, float radius = 0.65f, string colorMarker = "ff60df", string colorOutline = "00FFFFFF") {
var marker = new GameObject().AddComponent<CustomMapMarker>();
marker.name = name;
marker.displayName = displayName;
marker.radius = radius;
marker.position = position;
marker.refreshRate = refreshRate;
ColorUtility.TryParseHtmlString($"#{colorMarker}", out marker.color1);
ColorUtility.TryParseHtmlString($"#{colorOutline}", out marker.color2);
}
private void RemoveMarkers() {
foreach (var marker in UnityEngine.Object.FindObjectsOfType<CustomMapMarker>()) {
UnityEngine.Object.Destroy(marker);
}
}
private const string genericPrefab = "assets/prefabs/tools/map/genericradiusmarker.prefab";
private const string vendingPrefab = "assets/prefabs/deployable/vendingmachine/vending_mapmarker.prefab";
#region Scripts
private class CustomMapMarker : MonoBehaviour {
private VendingMachineMapMarker vending;
private MapMarkerGenericRadius generic;
public BaseEntity parent;
private bool asChild;
public float radius;
public Color color1;
public Color color2;
public string displayName;
public float refreshRate;
public Vector3 position;
public bool placedByPlayer;
private void Start() {
transform.position = position;
asChild = parent != null;
CreateMarkers();
}
private void CreateMarkers() {
vending = GameManager.server.CreateEntity(vendingPrefab, position).GetComponent<VendingMachineMapMarker>();
vending.markerShopName = displayName;
vending.enableSaving = false;
vending.Spawn();
generic = GameManager.server.CreateEntity(genericPrefab).GetComponent<MapMarkerGenericRadius>();
generic.color1 = color1;
generic.color2 = color2;
generic.radius = radius;
generic.alpha = 1f;
generic.enableSaving = false;
generic.SetParent(vending);
generic.Spawn();
UpdateMarkers();
if (refreshRate > 0f) {
if (asChild) {
InvokeRepeating(nameof(UpdatePosition), refreshRate, refreshRate);
}
else {
InvokeRepeating(nameof(UpdateMarkers), refreshRate, refreshRate);
}
}
}
private void UpdatePosition() {
if (asChild == true) {
if (parent.IsValid() == false) {
Destroy(this);
return;
}
else {
var pos = parent.transform.position;
transform.position = pos;
vending.transform.position = pos;
}
}
UpdateMarkers();
}
private void UpdateMarkers() {
vending.SendNetworkUpdate();
generic.SendUpdate();
}
private void DestroyMakers() {
if (vending.IsValid()) {
vending.Kill();
}
if (generic.IsValid()) {
generic.Kill();
}
}
private void OnDestroy() {
DestroyMakers();
}
}
#endregion
#endregion
private object CanBuild(Planner planner, Construction prefab, Construction.Target target) {
if (Vector3.Distance(target.position, vector) < 65) {
BasePlayer player = planner?.GetOwnerPlayer();
if (player != null) PrintToChat(player, lang.GetMessage("ChinookBuild", this));
return false;
}
return null;
}
Vector3 vector;
private void ChinookHelicopterCall() {
#region RandomSpawnPosition
float x = TerrainMeta.Size.x;
float y = 70f;
Vector3 val = Vector3Ex.Range(-1f, 1f);
val.y = 0f;
val.Normalize();
val *= x * 1f;
val.y = y;
#endregion
CH47Helicopter ChinookEnt = GameManager.server.CreateEntity("assets/prefabs/npc/ch47/ch47scientists.entity.prefab", val, new Quaternion(0f, 0f, 0f, 0f), true) as CH47Helicopter;
if (!ChinookEnt) return;
CH47HelicopterAIController ChinookAI = ChinookEnt.GetComponent<CH47HelicopterAIController>();
ChinookAI.Spawn();
ChinookAI.SetMaxHealth(900000f);
ChinookAI.health = 900000f;
ChinookAI.Heal(900000f);
vector = GetEventPosition();
CreateMarker(vector, 5, "ОСОБЫЙ ГРУЗ", "ОСОБЫЙ ГРУЗ");
string Cvadrat = "";
Cvadrat = GetGridString(vector);
ChinookAI.SetMoveTarget(vector);
ReplyWithHelper(String.Format(lang.GetMessage("ChinookStart", this), Cvadrat));
Subscribe(nameof(CanBuild));
ChinookAI.SetLandingTarget(new Vector3(vector.x, vector.y + 90f, vector.z));
Timer timers = null;
Vector3 CheckPos = new Vector3(0, 0, 0);
int i = 0;
timers = timer.Every(10, () => {
if (ChinookAI.IsDead()) {
ReplyWithHelper(lang.GetMessage("ChinookIsDead", this));
PrintWarning("Cninook is dead");
RemoveMarkers();
Unsubscribe(nameof(CanBuild));
timers.Destroy();
return;
}
if (Math.Floor(ChinookAI.GetPosition().MagnitudeXZ()) == Math.Floor(vector.MagnitudeXZ())) {
ReplyWithHelper(String.Format(lang.GetMessage("ChinookFinish", this), Cvadrat, FormatTime(TimeSpan.FromSeconds(config.chinook.TimeStamp))));
timers.Destroy();
timer.Once(config.chinook.TimeStamp, () => {
ReplyWithHelper(String.Format(lang.GetMessage("ChinookIsDrop", this), Cvadrat));
Vector3 pos = ChinookAI.transform.position + Vector3.down * 10f;
CreateCrate(pos);
ChinookAI.ClearLandingTarget();
ChinookAI.DestroyShared();
}
);
}
#region Костыль века
if (i > 10 && Math.Floor(ChinookAI.GetPosition().MagnitudeXZ()) != Math.Floor(vector.MagnitudeXZ()) && Math.Floor(CheckPos.MagnitudeXZ()) == Math.Floor(ChinookAI.GetPosition().MagnitudeXZ())) {
ReplyWithHelper(lang.GetMessage("ChinookIsDead", this));
PrintWarning("Cninook is dead++");
Unsubscribe(nameof(CanBuild));
RemoveMarkers();
ChinookAI.Kill();
timers.Destroy();
return;
}
if (i > 10) {
CheckPos = ChinookAI.transform.position;
}
i++;
#endregion
}
);
}
#region Узнаем квадрат
private string GetGridString(Vector3 position) {
Vector2 adjPosition = new Vector2((World.Size / 2f) + position.x, (World.Size / 2f) - position.z);
return $"{NumberToString((int)(adjPosition.x / 150f))}{(int)(adjPosition.y / 150f)}";
}
private string NumberToString(int number) {
bool a = number > 25;
Char c = (Char)(65 + (a ? number - 26 : number));
return a ? "A" + c : c.ToString();
}
#endregion
private void CreateCrate(Vector3 position) {
var CrateEnt = GameManager.server.CreateEntity("assets/prefabs/deployable/chinooklockedcrate/codelockedhackablecrate.prefab", position, Quaternion.Euler(0f, Oxide.Core.Random.Range(0f, 360f), 0f)).GetComponent<HackableLockedCrate>();
CrateEnt.Spawn();
CrateEnt.inventory.itemList.Clear();
CrateEnt.OwnerID = 12436;
for (int i = 0; i < config.chinook.itemsDrops.Count; i++) {
var cfg = config.chinook.itemsDrops[i];
bool goodChance = UnityEngine.Random.Range(0, 100) >= (100 - cfg.DropChance);
if (goodChance && CrateEnt.inventory.itemList.Count <= config.chinook.MaxItem) {
if (cfg.BluePrint) {
var bp = ItemManager.Create(ResearchTable.GetBlueprintTemplate());
bp.blueprintTarget = ItemManager.FindItemDefinition(cfg.Shortname).itemid;
bp.MoveToContainer(CrateEnt.inventory);
}
else {
Item GiveItem = ItemManager.CreateByName(cfg.Shortname, Oxide.Core.Random.Range(cfg.MinimalAmount, cfg.MaximumAmount), cfg.SkinID);
if(!string.IsNullOrEmpty(cfg.DisplayName)) {
GiveItem.name = cfg.DisplayName;
}
GiveItem.MoveToContainer(CrateEnt.inventory);
}
}
}
CrateEnt.inventory.capacity = CrateEnt.inventory.itemList.Count;
CrateEnt.inventory.MarkDirty();
CrateEnt.SendNetworkUpdate();
}
#region Hooks
void OnCrateHack(HackableLockedCrate crate) {
if(crate.OwnerID == 12436) {
ReplyWithHelper(String.Format(lang.GetMessage("ChinookIsDropHack", this), GetGridString(crate.transform.position)));
}
}
void OnCrateHackEnd(HackableLockedCrate crate) {
if (crate.OwnerID == 12436) {
ReplyWithHelper(lang.GetMessage("ChinookIsDropHackEnd", this));
}
}
void OnLootEntity(BasePlayer player, BaseEntity entity) {
if (entity is HackableLockedCrate) {
if(entity.OwnerID == 12436) {
ReplyWithHelper(String.Format(lang.GetMessage("ChinookIsDropHackEndLoot", this), player.displayName));
RemoveMarkers();
timer.Once(30, ()=> Unsubscribe(nameof(CanBuild)));
entity.OwnerID = 85674856;
}
}
}
void Unload() {
Unsubscribe(nameof(CanBuild));
RemoveMarkers();
}
void OnServerInitialized() {
LoadConfigVars();
LoadDefaultMessages();
Unsubscribe(nameof(CanBuild));
timer.Every(config.chinook.TimeChinook, () => {
if (BasePlayer.activePlayerList.Count > config.chinook.PlayersMin) {
ChinookHelicopterCall();
}
}
);
PrintWarning($"Ивент будет запущен через {FormatTime(TimeSpan.FromSeconds(config.chinook.TimeChinook))}");
}
#endregion
public void ReplyWithHelper(string message, string[] args = null) {
if (args != null) message = string.Format(message, args);
BasePlayer.activePlayerList.ToList().ForEach(player => {
player.SendConsoleCommand("chat.add 0", new object[2] {
76561198865777479, string.Format("<size=16><color={2}>{0}</color>:</size>\n{1}", "Особый груз", message, "#3B85F5B1")
}
);
}
);
}
#region SpawnMetods
SpawnFilter filter = new SpawnFilter();
List<Vector3> monuments = new List<Vector3>();
static float GetGroundPosition(Vector3 pos) {
float y = TerrainMeta.HeightMap.GetHeight(pos);
RaycastHit hit;
if (UnityEngine.Physics.Raycast(new Vector3(pos.x, pos.y + 200f, pos.z), Vector3.down, out hit, Mathf.Infinity, LayerMask.GetMask(new[] {
"Terrain", "World", "Default", "Construction", "Deployed"
}
)) && !hit.collider.name.Contains("rock_cliff")) return Mathf.Max(hit.point.y, y);
return y;
}
public Vector3 RandomDropPosition() {
var vector = Vector3.zero;
float num = 1000f, x = TerrainMeta.Size.x / 3;
do {
vector = Vector3Ex.Range(-x, x);
}
while (filter.GetFactor(vector) == 0f && (num -= 1f) > 0f);
float max = TerrainMeta.Size.x / 2;
float height = TerrainMeta.HeightMap.GetHeight(vector);
vector.y = height;
return vector;
}
List<int> BlockedLayers = new List<int> {
(int)Layer.Water, (int)Layer.Construction, (int)Layer.Trigger, (int)Layer.Prevent_Building, (int)Layer.Deployed, (int)Layer.Tree
}
;
static int blockedMask = LayerMask.GetMask(new[] {
"Player (Server)", "Trigger", "Prevent Building"
}
);
public Vector3 GetSafeDropPosition(Vector3 position) {
RaycastHit hit;
position.y += 200f;
if (UnityEngine.Physics.Raycast(position, Vector3.down, out hit)) {
if (hit.collider?.gameObject == null) return Vector3.zero;
string ColName = hit.collider.name;
if (!BlockedLayers.Contains(hit.collider.gameObject.layer) && ColName != "MeshColliderBatch" && ColName != "iceberg_3" && ColName != "iceberg_2" && !ColName.Contains("rock_cliff")) {
position.y = Mathf.Max(hit.point.y, TerrainMeta.HeightMap.GetHeight(position));
var colliders = Pool.GetList<Collider>();
Vis.Colliders(position, 1, colliders, blockedMask, QueryTriggerInteraction.Collide);
bool blocked = colliders.Count > 0;
Pool.FreeList<Collider>(ref colliders);
if (!blocked) return position;
}
}
return Vector3.zero;
}
public Vector3 GetEventPosition() {
var eventPos = Vector3.zero;
int maxRetries = 100;
monuments = UnityEngine.Object.FindObjectsOfType<MonumentInfo>().Select(monument => monument.transform.position).ToList();
do {
eventPos = GetSafeDropPosition(RandomDropPosition());
foreach (var monument in monuments) {
if (Vector3.Distance(eventPos, monument) < 150f) {
eventPos = Vector3.zero;
break;
}
}
}
while (eventPos == Vector3.zero && --maxRetries > 0);
eventPos.y = GetGroundPosition(eventPos);
if (eventPos.y < 0) GetEventPosition();
return eventPos;
}
#endregion
#region TimeFormat
public static string FormatTime(TimeSpan time, int maxSubstr = 5, string language = "ru") {
string result = string.Empty;
switch (language) {
case "ru" : int i = 0;
if (time.Days != 0 && i < maxSubstr) {
if (!string.IsNullOrEmpty(result)) result += " ";
result += $"{Format(time.Days, "дней", "дня", "день")}";
i++;
}
if (time.Hours != 0 && i < maxSubstr) {
if (!string.IsNullOrEmpty(result)) result += " ";
result += $"{Format(time.Hours, "часов", "часа", "час")}";
i++;
}
if (time.Minutes != 0 && i < maxSubstr) {
if (!string.IsNullOrEmpty(result)) result += " ";
result += $"{Format(time.Minutes, "минут", "минуты", "минута")}";
i++;
}
if (time.Seconds != 0 && i < maxSubstr) {
if (!string.IsNullOrEmpty(result)) result += " ";
result += $"{Format(time.Seconds, "секунд", "секунды", "секунд")}";
i++;
}
break;
case "en" : result = string.Format("{0}{1}{2}{3}", time.Duration().Days > 0 ? $"{time.Days:0} day{(time.Days == 1 ? String.Empty : "s")}, " : string.Empty, time.Duration().Hours > 0 ? $"{time.Hours:0} hour{(time.Hours == 1 ? String.Empty : "s")}, " : string.Empty, time.Duration().Minutes > 0 ? $"{time.Minutes:0} minute{(time.Minutes == 1 ? String.Empty : "s")}, " : string.Empty, time.Duration().Seconds > 0 ? $"{time.Seconds:0} second{(time.Seconds == 1 ? String.Empty : "s")}" : string.Empty);
if (result.EndsWith(", ")) result = result.Substring(0, result.Length - 2);
if (string.IsNullOrEmpty(result)) result = "0 seconds";
break;
}
return result;
}
public static long TimeToSeconds(string time) {
time = time.Replace(" ", "").Replace("d", "d ").Replace("h", "h ").Replace("m", "m ").Replace("s", "s ").TrimEnd(' ');
var arr = time.Split(' ');
long seconds = 0;
foreach (var s in arr) {
var n = s.Substring(s.Length - 1, 1);
var t = s.Remove(s.Length - 1, 1);
int d = int.Parse(t);
switch (n) {
case "s" : seconds += d;
break;
case "m" : seconds += d * 60;
break;
case "h" : seconds += d * 3600;
break;
case "d" : seconds += d * 86400;
break;
}
}
return seconds;
}
private static string Format(int units, string form1, string form2, string form3) {
var tmp = units % 10;
if (units >= 5 && units <= 20 || tmp >= 5 && tmp <= 9) return $"{units} {form1}";
if (tmp >= 2 && tmp <= 4) return $"{units} {form2}";
return $"{units} {form3}";
}
#endregion
}
}