C#:
using System;
using System.Collections.Generic;
using ConVar;
using Newtonsoft.Json;
using Oxide.Core.Plugins;
using UnityEngine;
using Oxide.Game.Rust.Cui;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections;
using Oxide.Core;
namespace Oxide.Plugins {
[Info("IQHeadReward", "SkuliDropek", "1.0.9")]
[Description("Reward your heads")]
class IQHeadReward : RustPlugin {
/// <summary>
/// Обновление 1.0.х
/// - Переписал метод проверки на кланы
/// - Добавлена возможность включения и отключения маркера для игрока и ящика с наградой отдельно!
/// - Убрал лог загрузки изображений в консоль от API
/// </summary>
#region Vars
private const Boolean LanguageRu = true;
public const String PermissionImmunitete = "iqheadreward.invise";
public Dictionary<BaseEntity, CustomMapMarker> MapMarkers = new Dictionary<BaseEntity, CustomMapMarker>();
static Double CurrentTime() => Facepunch.Math.Epoch.Current;
public enum TypeReward {
Item, Command, IQEconomics
}
public enum TypeTask {
New, Retry
}
String PrefabStash = "assets/prefabs/deployable/small stash/small_stash_deployed.prefab";
String PrefabBarricade = "assets/prefabs/deployable/door barricades/door_barricade_dbl_a.prefab";
#endregion
#region Reference
[PluginReference]
Plugin ImageLibrary, IQChat, IQEconomic, IQPlagueSkill, Friends, Clans, Battles, Duel, Duelist, IQRankSystem;
#region ImageLibrary
private String GetImage(String fileName, UInt64 skin = 0) {
var imageId = (String)plugins.Find("ImageLibrary").CallHook("GetImage", fileName, skin);
if (!string.IsNullOrEmpty(imageId)) return imageId;
return String.Empty;
}
public Boolean AddImage(String url, String shortname, UInt64 skin = 0) => (Boolean)ImageLibrary?.Call("AddImage", url, shortname, skin);
public void SendImage(BasePlayer player, String imageName, UInt64 imageId = 0) => ImageLibrary?.Call("SendImage", player, imageName, imageId);
public Boolean HasImage(String imageName) => (Boolean)ImageLibrary?.Call("HasImage", imageName);
#endregion
#region Friends, Clans , Duel
public Boolean IsFriends(UInt64 userID, UInt64 targetID) {
if (Friends) return (Boolean)Friends?.Call("HasFriend", userID, targetID);
else return false;
}
private bool IsClans(String userID, String targetID) {
if (Clans) {
String TagUserID = (String)Clans?.Call("GetClanOf", userID);
String TagTargetID = (String)Clans?.Call("GetClanOf", targetID);
if (TagUserID == null && TagTargetID == null) return false;
return (bool)(TagUserID == TagTargetID);
}
else return false;
}
public Boolean IsDuel(UInt64 userID) {
if (Battles) return (Boolean)Battles?.Call("IsPlayerOnBattle", userID);
else if (Duel) return (Boolean)Duel?.Call("IsPlayerOnActiveDuel", BasePlayer.FindByID(userID));
else if (Duelist) return (Boolean)Duelist?.Call("inEvent", BasePlayer.FindByID(userID));
else return false;
}
private Dictionary<UInt64, List<UInt64>> WantedTeams = new Dictionary<UInt64, List<UInt64>>();
private Boolean IsTeamController(BasePlayer Wanted) => WantedTeams.ContainsKey(Wanted.Team.teamID) && config.Setting.AntiAbuse;
private void TeamControllerAdd(BasePlayer Wanted) {
if (Wanted == null && !config.Setting.AntiAbuse) return;
RelationshipManager.PlayerTeam Team = Wanted.Team;
if (Team == null) return;
if (!IsTeamController(Wanted)) WantedTeams.Add(Team.teamID, Team.members);
else WantedTeams[Team.teamID] = WantedTeams[Team.teamID].Concat(Team.members).ToList();
}
private void TeamControllerRemove(BasePlayer Wanted) {
if (Wanted == null || !config.Setting.AntiAbuse) return;
RelationshipManager.PlayerTeam Team = Wanted.Team;
if (IsTeamController(Wanted)) WantedTeams.Remove(Team.teamID);
}
#endregion
#region IQEconomics
public String IQEcoMoney => (String)IQEconomic?.Call("API_GET_MONEY_IL");
public void IQEconomicSetBalance(UInt64 userID, Int32 Balance) => IQEconomic?.Call("API_SET_BALANCE", userID, Balance);
Int32 IQEconomicGetBalance(UInt64 userID) => IQEconomic == null ? 0 : (Int32)IQEconomic.Call("API_GET_BALANCE", userID);
void IQEconomicRemoveBalance(UInt64 userID, Int32 Balance) => IQEconomic?.Call("API_REMOVE_BALANCE", userID, Balance);
#endregion
#region IQPlagueSkill
public Boolean IQPlagueSkillUse(BasePlayer player) => (Boolean)IQPlagueSkill.Call("API_HEAD_REWARD_SKILL", player);
#endregion
#region IQChat
public void SendChat(BasePlayer player, String Message, Chat.ChatChannel channel = Chat.ChatChannel.Global) {
var Chat = config.Setting.ChatSetting;
if (IQChat) IQChat?.Call("API_ALERT_PLAYER", player, Message, Chat.CustomPrefix, Chat.CustomAvatar);
else player.SendConsoleCommand("chat.add", channel, 0, Message);
}
#endregion
#region RaidBlocked
public Boolean IsRaidBlocked(BasePlayer player) {
var ret = Interface.Call("CanTeleport", player) as String;
if (ret != null) return true;
else return false;
}
#endregion
#region IQRankSystem
Boolean IsRank(UInt64 userID, String Key) {
if (!IQRankSystem) return false;
return (Boolean)IQRankSystem?.Call("API_GET_AVAILABILITY_RANK_USER", userID, Key);
}
String GetRankName(String Key) {
String Rank = string.Empty;
if (!IQRankSystem) return Rank;
return (String)IQRankSystem?.Call("API_GET_RANK_NAME", Key);
}
#endregion
#endregion
#region Data
private Dictionary<UInt64, HeadTask> PrePlayerHeads = new Dictionary<UInt64, HeadTask>();
private Dictionary<UInt64, List<Configuration.Settings.ItemList>> DistributionPlayerReturned = new Dictionary<UInt64, List<Configuration.Settings.ItemList>>();
[JsonProperty(LanguageRu ? "Задания на головы" : "Tasks for heads")]
private List<HeadTask> PlayerHeads = new List<HeadTask>();
public class HeadTask {
public String WantedName;
public UInt64 WantedID;
public Double Cooldown;
public Dictionary<UInt64, List<Configuration.Settings.ItemList>> RewardList;
public Double CooldownItem;
}
void ReadData() {
PlayerHeads = Oxide.Core.Interface.Oxide.DataFileSystem.ReadObject<List<HeadTask>>("IQSystem/IQHeadReward/PlayerHeads");
WantedTeams = Oxide.Core.Interface.Oxide.DataFileSystem.ReadObject<Dictionary<UInt64, List<UInt64>>>("IQSystem/IQHeadReward/PlayersHeadsTeam");
DistributionPlayerReturned = Oxide.Core.Interface.Oxide.DataFileSystem.ReadObject<Dictionary<UInt64, List<Configuration.Settings.ItemList>>>("IQSystem/IQHeadReward/DistributionPlayerReturned");
}
void WriteData() {
Oxide.Core.Interface.Oxide.DataFileSystem.WriteObject("IQSystem/IQHeadReward/PlayerHeads", PlayerHeads);
Oxide.Core.Interface.Oxide.DataFileSystem.WriteObject("IQSystem/IQHeadReward/PlayersHeadsTeam", WantedTeams);
Oxide.Core.Interface.Oxide.DataFileSystem.WriteObject("IQSystem/IQHeadReward/DistributionPlayerReturned", DistributionPlayerReturned);
}
#endregion
#region Configuration
private static Configuration config = new Configuration();
public class Configuration {
[JsonProperty("Настройка плагина | Settings plugin")]
public Settings Setting = new Settings();
internal class Settings {
[JsonProperty("Настройки IQChat | Settings IQChat")]
public ChatSettings ChatSetting = new ChatSettings();
[JsonProperty("Настройки IQRankSystem | Settings IQRankSystem")]
public IQRankSystem IQRankSystemSetting = new IQRankSystem();
[JsonProperty("Настройки UI уведомления | Notification UI Settings")]
public AlertUI AlertUISetting = new AlertUI();
[JsonProperty("Настройка создания объявления за голову игроками | Setting up the creation of ads for the head of players")]
public CustomCreated CustomCreatedSetting = new CustomCreated();
[JsonProperty("Настройка метки на карте для игрока | Setting up a placemark on the map for the player")]
public MapMark mapMark = new MapMark();
internal class IQRankSystem {
[JsonProperty("Использовать IQRankSystem [true-да/false-нет] (При наличии ранга игрок сможет создавать объявления на голову игрока) | Use IQRankSystem [true-yes/false-no] (If there is a rank, the player will be able to create ads on the player's head)")]
public Boolean UseRank = false;
[JsonProperty("Впишите ключ ранга, который требуется для разблокировки возможности | Enter the rank key that is required to unlock the feature")]
public String Rank = "";
}
internal class MapMark {
[JsonProperty("Включить отображение игрока на G карте | Enable the display of the player on the G map")]
public Boolean UseMark;
[JsonProperty("Включить отображение ящиков с наградой для игрока на G карте | Enable display of reward boxes for the player on the G map")]
public Boolean UseMarkCrates;
[JsonProperty("Радиус отображения метки на карте | The radius of the placemark display on the map")]
public Single Radius;
[JsonProperty("Время обновления метки (В секундах) | Time to update the placemark (In seconds)")]
public Single RefreshRate;
[JsonProperty("Название метки (%NAME% - выведет имя игрока) | Marker name (%NAME% - displays the player's name)")]
public String DisplayName;
[JsonProperty("HEX цвет метки | HEX Marker color")]
public String Color;
[JsonProperty("HEX цвет обводки метки | HEX color of the marker outline")]
public String OutLineColor;
}
[JsonProperty("Включить внутреннюю защиту от попытки абуза со своей тимой | Enable internal protection against an attempt to abuse with your team")]
public Boolean AntiAbuse;
[JsonProperty("Автоматический поиск игроков(true - включен/false - отключен) | Automatic search for players(true-enabled/false-disabled)")]
public Boolean TurnAutoFilling;
[JsonProperty("Через сколько искать игроков для задания цели | After how long to search for players to set a goal")]
public Int32 TimeFinding;
[JsonProperty("Оповещать всех игроков о том,что появилась новая награда за голову(ture - да/false - нет) | Notify all players that a new head reward has appeared(ture-yes/false-no)")]
public Boolean UseAlertHead;
[JsonProperty("Максимальное количество наград за голову(Исходя из списка наград,будет выбираться рандомное количество) | The maximum number of awards per head(Based on the list of awards, a random number will be selected)")]
public Int32 MaxReward;
[JsonProperty("Настройка наград за голову(Рандомно будет выбираться N количество) | Setting up head rewards(N numbers will be randomly selected)")]
public List<ItemList> itemLists;
public class ItemList {
[JsonProperty("Тип награды(от этого зависит,что будут выдавать) : 0 - Предмет , 1 - Команда, 2 - IQEconomic | The type of reward (it depends on what will be given): 0-Item, 1-Command, 2-IQEconomic")]
public TypeReward TypeRewards;
[JsonProperty("Команда(%STEAMID% - замениться на ID игрока) | Command (%STEAMID% - change to player ID)")]
public String Command;
[JsonProperty("Отображаемое имя | Display name")]
public String DisplayName;
[JsonProperty("Shortname")]
public String Shortname;
[JsonProperty("SkinID")]
public UInt64 SkinID;
[JsonProperty("Минимальное количество | Minimal amount")]
public Int32 AmountMin;
[JsonProperty("Максимальное количество | Maximum amount")]
public Int32 AmountMax;
[JsonProperty("Настройки IQEconomic | Setting IQEconomic")]
public IQEconomics IQEconomic = new IQEconomics();
internal class IQEconomics {
[JsonProperty("IQEconomic : Минимальный баланс | IQEconomic : Minimal balance")]
public Int32 MinBalance;
[JsonProperty("IQEconomic : Максимальный баланс | IQEconomic : Maximum balance")]
public Int32 MaxBalance;
}
}
internal class ChatSettings {
[JsonProperty("IQChat : Кастомный префикс в чате | IQChat : Custom prefix in the chat")]
public String CustomPrefix;
[JsonProperty("IQChat : Кастомный аватар в чате(Если требуется) | IQChat : Custom avatar in the chat(If required)")]
public String CustomAvatar;
}
internal class AlertUI {
[JsonProperty("Использовать UI уведомление о том,что за голову игрока назначена награда | Use the UI notification that a reward is assigned for the player's head")]
public Boolean UseAlertUI;
[JsonProperty("Возможность скрывать игрокам UI уведомление о том,что за голову назначена награда (по клику на уведомление) (true - да/false - нет) | The ability to hide the UI notification to players that a reward is assigned for the head (by clicking on the notification) (true-yes/false-no)")]
public Boolean UserCloseUI;
[JsonProperty("Ссылка на PNG | Link PNG (En Image - https://i.imgur.com/S4NxpUa.png)")]
public String PNG;
[JsonProperty("AnchorMin")]
public String AnchorMin;
[JsonProperty("AnchorMax")]
public String AnchorMax;
[JsonProperty("OffsetMin")]
public String OffsetMin;
[JsonProperty("OffsetMax")]
public String OffsetMax;
}
internal class CustomCreated {
[JsonProperty("Настройка возврата предметов при предсоздании награды за голову(не объявив ее) | Setting up the return of items when pre-creating a head reward(without declaring it)")]
public ReturnPreCreated ReturnCreated = new ReturnPreCreated();
[JsonProperty("Разрешить создавать игрокам использовать команду /ih во время рейдблока(true - да/false - нет) | Allow players to create and use the /ih command during a raid block(true-yes/false-no)")]
public Boolean UseCommandBlock = false;
[JsonProperty("Разрешить создавать игрокам награды за голову | Allow players to create rewards for their heads")]
public Boolean UseCustomReward = false;
[JsonProperty("Разрешить игрокам выбирать время из списка иначе будет устанавливаться из конфига по умолчанию | Allow players to choose the time from the list otherwise it will be set from the default config")]
public Boolean UseCutomTime = false;
[JsonProperty("Максимальное количество предметов в качестве награды от одного игрока | The maximum number of items as a reward from one player")]
public Int32 MaximumRewardCountUser = 10;
[JsonProperty("Настройки времени | Time Settings")]
public TimeSettings TimeSetting = new TimeSettings();
internal class ReturnPreCreated {
[JsonProperty("Возвращать предметы игрокам через время, которые они вложили в предсоздания объявления (Не создав его до конца) | Return items to players after the time that they have invested in the pre-creation of the ad (Without creating it until the end)")]
public Boolean UseReturnTimer = true;
[JsonProperty("Время через которое будет возврат | The time after which the refund will be made")]
public Int32 Time = 60;
}
internal class TimeSettings {
[JsonProperty("Время по умолчанию(секунды) | Default time(seconds)")]
public Int32 TimeDefault = 600;
[JsonProperty("Настраиваемый список для выбора времени игркоками | Customizable list for selecting the time of playcocks")]
public List<TimeCreatedMore> CustomTimeSettings = new List<TimeCreatedMore>();
internal class TimeCreatedMore {
[JsonProperty("Использовать поддержку IQEconomic | Use IQEconomic support")]
public Boolean IQEconomic_CustomTime = false;
[JsonProperty("Время(секунды) | Time(seconds)")]
public Int32 Time = 0;
[JsonProperty("Цена за установку данного времени, должна быть поддержка IQEconomic | The price for the installation of this time, there must be support for IQEconomic")]
public Int32 IQEconomic_Balance = 0;
}
}
}
}
public static Configuration GetNewConfiguration() {
return new Configuration {
Setting = new Settings {
TurnAutoFilling = true, AntiAbuse = true, TimeFinding = 600, UseAlertHead = true, MaxReward = 3, IQRankSystemSetting = new Settings.IQRankSystem {
Rank = "", UseRank = false,
}
, mapMark = new Settings.MapMark {
Color = "#ff4948", OutLineColor = "#333336", DisplayName = "%NAME%", Radius = 0.65f, RefreshRate = 0.2f, UseMark = true, UseMarkCrates = true,
}
, CustomCreatedSetting = new Settings.CustomCreated {
UseCommandBlock = false, UseCutomTime = true, UseCustomReward = true, MaximumRewardCountUser = 10, ReturnCreated = new Settings.CustomCreated.ReturnPreCreated {
Time = 60, UseReturnTimer = true
}
, TimeSetting = new Settings.CustomCreated.TimeSettings {
TimeDefault = 600, CustomTimeSettings = new List<Settings.CustomCreated.TimeSettings.TimeCreatedMore> {
new Settings.CustomCreated.TimeSettings.TimeCreatedMore {
Time = 2500, IQEconomic_Balance = 230, IQEconomic_CustomTime = true,
}
, new Settings.CustomCreated.TimeSettings.TimeCreatedMore {
Time = 3000, IQEconomic_Balance = 250, IQEconomic_CustomTime = true,
}
, new Settings.CustomCreated.TimeSettings.TimeCreatedMore {
Time = 1000, IQEconomic_Balance = 250, IQEconomic_CustomTime = false,
}
,
}
}
}
, itemLists = new List<Settings.ItemList> {
new Settings.ItemList {
TypeRewards = TypeReward.Item, Command = "", DisplayName = "Kalash", Shortname = "rifle.ak", AmountMin = 1, AmountMax = 1, SkinID = 0, IQEconomic = new Settings.ItemList.IQEconomics {
MinBalance = 1, MaxBalance = 10
}
,
}
, new Settings.ItemList {
TypeRewards = TypeReward.Item, Command = "", DisplayName = "", Shortname = "rifle.ak", AmountMin = 1, AmountMax = 1, SkinID = 0, IQEconomic = new Settings.ItemList.IQEconomics {
MinBalance = 1, MaxBalance = 10
}
,
}
, new Settings.ItemList {
TypeRewards = TypeReward.Item, Command = "", DisplayName = "", Shortname = "wood", AmountMin = 3000, AmountMax = 6000, SkinID = 0, IQEconomic = new Settings.ItemList.IQEconomics {
MinBalance = 1, MaxBalance = 10
}
,
}
, new Settings.ItemList {
TypeRewards = TypeReward.Item, Command = "", DisplayName = "", Shortname = "metal.fragments", AmountMin = 100, AmountMax = 2000, SkinID = 0, IQEconomic = new Settings.ItemList.IQEconomics {
MinBalance = 1, MaxBalance = 10
}
,
}
, new Settings.ItemList {
TypeRewards = TypeReward.Item, Command = "", DisplayName = "", Shortname = "skull.human", AmountMin = 1, AmountMax = 10, SkinID = 0, IQEconomic = new Settings.ItemList.IQEconomics {
MinBalance = 1, MaxBalance = 10
}
,
}
, new Settings.ItemList {
TypeRewards = TypeReward.Item, Command = "", DisplayName = "", Shortname = "scrap", AmountMin = 111, AmountMax = 2222, SkinID = 0, IQEconomic = new Settings.ItemList.IQEconomics {
MinBalance = 1, MaxBalance = 10
}
,
}
, new Settings.ItemList {
TypeRewards = TypeReward.Item, Command = "", DisplayName = "", Shortname = "skull.wolf", AmountMin = 1, AmountMax = 15, SkinID = 0, IQEconomic = new Settings.ItemList.IQEconomics {
MinBalance = 1, MaxBalance = 10
}
,
}
, new Settings.ItemList {
TypeRewards = TypeReward.Item, Command = "", DisplayName = "", Shortname = "sulfur", AmountMin = 1333, AmountMax = 1532, SkinID = 0, IQEconomic = new Settings.ItemList.IQEconomics {
MinBalance = 1, MaxBalance = 10
}
,
}
, new Settings.ItemList {
TypeRewards = TypeReward.Command, Command = "say %STEAMID%", DisplayName = "", Shortname = "", AmountMin = 0, AmountMax = 0, SkinID = 0, IQEconomic = new Settings.ItemList.IQEconomics {
MinBalance = 1, MaxBalance = 10
}
,
}
,
}
, ChatSetting = new Settings.ChatSettings {
CustomAvatar = "", CustomPrefix = "[<color=#CC3226>IQHeadReward</color>]\n"
}
, AlertUISetting = new Settings.AlertUI {
UseAlertUI = true, UserCloseUI = false, PNG = "https://i.imgur.com/QVatu3D.png", AnchorMin = "0 1", AnchorMax = "0 1", OffsetMin = "0 -68.056", OffsetMax = "273.878 0"
}
,
}
,
}
;
}
}
protected override void LoadConfig() {
base.LoadConfig();
try {
config = Config.ReadObject<Configuration>();
if (config == null) LoadDefaultConfig();
}
catch {
PrintWarning("Error #87" + $"configuration readings 'oxide/config/{Name}', creating a new configuration! #45");
LoadDefaultConfig();
}
NextTick(SaveConfig);
}
protected override void LoadDefaultConfig() => config = Configuration.GetNewConfiguration();
protected override void SaveConfig() => Config.WriteObject(config);
#endregion
#region Metods
private void FillingPlayer() {
BasePlayer RandomPlayer = BasePlayer.activePlayerList.Where(p => PlayerHeads.Count(x => p.userID == x.WantedID) == 0 && !p.IsDead() && !permission.UserHasPermission(p.UserIDString, PermissionImmunitete)).ToList().GetRandom();
if (RandomPlayer == null) return;
List<Configuration.Settings.ItemList> RewardList = config.Setting.itemLists;
Int32 MaxReward = RewardList.Count <= config.Setting.MaxReward ? RewardList.Count : config.Setting.MaxReward;
if (IQPlagueSkill && IQPlagueSkillUse(RandomPlayer)) return;
HeadTask headTask = new HeadTask();
headTask.Cooldown = config.Setting.CustomCreatedSetting.TimeSetting.TimeDefault;
headTask.WantedID = RandomPlayer.userID;
headTask.WantedName = RandomPlayer.displayName;
UInt64 RandomID = UInt64.Parse(UnityEngine.Random.Range(0, 99999).ToString());
if (headTask.RewardList == null) headTask.RewardList = new Dictionary<ulong, List<Configuration.Settings.ItemList>>();
headTask.RewardList[RandomID] = GetRandomReward(RewardList, MaxReward);
PlayerHeads.Add(headTask);
if (config.Setting.UseAlertHead) foreach (BasePlayer player in BasePlayer.activePlayerList) SendChat(player, GetLang("NEW_HEAD", player.UserIDString, RandomPlayer.displayName));
if (config.Setting.AlertUISetting.UseAlertUI) AlertUI(RandomPlayer);
PlayerHeadAlert(RandomPlayer.userID, TypeTask.New);
TeamControllerAdd(RandomPlayer);
NextTick(() => {
CreateMarker(RandomPlayer);
}
);
}
#region Spawn Position Reward
private int maxTry = 250000;
private List<Vector3>[] patternPositionsAboveWater = new List<Vector3>[5];
private List<Vector3>[] patternPositionsUnderWater = new List<Vector3>[5];
private List<Vector3> busyPoints3D = new List<Vector3>();
private readonly Quaternion[] directions = {
Quaternion.Euler(90, 0, 0), Quaternion.Euler(0, 0, 90), Quaternion.Euler(0, 0, 180)
}
;
private void FillPatterns() {
Vector3[] startPositions = {
new Vector3(1, 0, 1), new Vector3(-1, 0, 1), new Vector3(-1, 0, -1), new Vector3(1, 0, -1)
}
;
patternPositionsAboveWater[0] = new List<Vector3> {
new Vector3(0, -0.6f, 0)
}
;
for (int loop = 1; loop < 5; loop++) {
patternPositionsAboveWater[loop] = new List<Vector3>();
for (int step = 0; step < loop * 2; step++) {
for (int pos = 0; pos < 4; pos++) {
Vector3 sPos = startPositions[pos] * step;
for (int rot = 0; rot < 3; rot++) {
Vector3 rPos = directions[rot] * sPos;
rPos.y = -0.6f;
patternPositionsAboveWater[loop].Add(rPos);
}
}
}
}
for (int i = 0; i < patternPositionsAboveWater.Length; i++) {
patternPositionsUnderWater[i] = new List<Vector3>();
foreach (var vPos in patternPositionsAboveWater[i]) {
var rPos = new Vector3(vPos.x, -0.6f, vPos.z);
patternPositionsUnderWater[i].Add(rPos);
}
}
}
public bool IsFlat(ref Vector3 position) {
List<Vector3>[] AboveWater = new List<Vector3>[5];
Array.Copy(patternPositionsAboveWater, AboveWater, patternPositionsAboveWater.Length);
for (int i = 0; i < AboveWater.Length; i++) {
for (int j = 0; j < AboveWater[i].Count; j++) {
Vector3 pPos = AboveWater[i][j];
Vector3 resultAbovePos = new Vector3(pPos.x + position.x, position.y + 0.6f, pPos.z + position.z);
Vector3 resultUnderPos = new Vector3(pPos.x + position.x, position.y - 0.6f, pPos.z + position.z);
if (resultAbovePos.y >= TerrainMeta.HeightMap.GetHeight(resultAbovePos) && resultUnderPos.y <= TerrainMeta.HeightMap.GetHeight(resultUnderPos)) {
}
else return false;
}
}
return true;
}
public bool IsDistancePoint(Vector3 point) {
bool result = busyPoints3D.Count(x => Vector3.Distance(point, x) < 20f) == 0;
return result;
}
private void GenerateSpawnPoints() {
for (int i = 0; i < 100; i++) {
maxTry -= 1;
Vector3 point3D = new Vector3();
Vector2 point2D = new Vector3(UnityEngine.Random.Range(-TerrainMeta.Size.x / 2, TerrainMeta.Size.x / 2), UnityEngine.Random.Range(-TerrainMeta.Size.z / 2, TerrainMeta.Size.z / 2));
point3D.x = point2D.x;
point3D.z = point2D.y;
point3D.y = TerrainMeta.HeightMap.GetHeight(point3D);
if (!IsFlat(ref point3D)) continue;
if (!Is3DPointValid(ref point3D)) continue;
if (!IsDistancePoint(point3D)) continue;
if (point3D != Vector3.zero) {
AcceptValue(ref point3D);
}
}
if (maxTry > 0) {
NextTick(() => {
GenerateSpawnPoints();
}
);
}
else {
PrintWarning(LanguageRu ? $"{busyPoints3D.Count} точек сгенерированно!" : $"{busyPoints3D.Count} points generated!");
maxTry = 250000;
}
}
private bool Is3DPointValid(ref Vector3 point) {
List<BuildingPrivlidge> cupboards = new List<BuildingPrivlidge>();
Vis.Entities(point, 5, cupboards);
if (UnityEngine.Physics.CheckSphere(point, 5, LayerMask.GetMask("Construction", "Default", "Deployed", "World", "Trigger", "Prevent Building")) || cupboards.Count > 0 || point.y < ConVar.Env.oceanlevel + 4f) {
return false;
}
return true;
}
private void AcceptValue(ref Vector3 point) {
busyPoints3D.Add(point);
}
#endregion
#region Spawn Reward
private void RewardCreated(List<Configuration.Settings.ItemList> Rewards, BasePlayer Killer) {
if (busyPoints3D == null) return;
foreach (Configuration.Settings.ItemList Reward in Rewards.Where(c => c.TypeRewards != TypeReward.Item)) {
switch (Reward.TypeRewards) {
case TypeReward.Command : {
rust.RunServerCommand(Reward.Command.Replace("%STEAMID%", Killer.UserIDString));
break;
}
case TypeReward.IQEconomics : {
IQEconomicSetBalance(Killer.userID, UnityEngine.Random.Range(Reward.IQEconomic.MinBalance, Reward.IQEconomic.MaxBalance));
break;
}
}
}
Double CrateCount = Math.Ceiling((Double)Rewards.Count(c => c.TypeRewards == TypeReward.Item) / (Double)6);
for (Int32 Count = 0; Count < CrateCount; Count++) {
Double SkipCount = (Double)Count * 6;
Vector3 RandomPosition = busyPoints3D.GetRandom();
CreatedCrate(Rewards.Where(c => c.TypeRewards == TypeReward.Item).Skip((Int32)SkipCount).ToList(), RandomPosition, Killer);
}
String CrateMessage = String.Empty;
if (CrateCount != 0) CrateMessage = GetLang("CHAT_ALERT_KILLED_REWARD_ITEM", Killer.UserIDString, CrateCount);
String OtherMessage = String.Empty;
if(Rewards.Count(c => c.TypeRewards != TypeReward.Item) != 0) OtherMessage = GetLang("CHAT_ALERT_KILLED_REWARD_OTHER", Killer.UserIDString, Rewards.Count(c => c.TypeRewards != TypeReward.Item));
String AllReward = $"{CrateMessage}\n{OtherMessage}";
String Message = GetLang("CHAT_ALERT_KILLED_REWARD_PLAYER", Killer.UserIDString, AllReward);
SendChat(Killer, Message);
}
private void CreatedCrate(List<Configuration.Settings.ItemList> Rewards, Vector3 Position, BasePlayer Killer) {
Vector3 SpawnPos = new Vector3 {
x = Position.x, y = TerrainMeta.HeightMap.GetHeight(Position), z = Position.z
}
;
StashContainer Container = (StashContainer)GameManager.server.CreateEntity(PrefabStash, SpawnPos);
Container.Spawn();
for (Int32 Item = 0; Item < Rewards.Count; Item++) {
Configuration.Settings.ItemList Reward = Rewards[Item];
Item ItemCreated = CreatedItem(Reward);
ItemCreated.MoveToContainer(Container.inventory);
}
BaseEntity Barricade = (BaseEntity)GameManager.server.CreateEntity(PrefabBarricade, new Vector3(SpawnPos.x, SpawnPos.y - 0.14f, SpawnPos.z - 1), Quaternion.Euler(new Vector3(90, 0, 0)));
Barricade.Spawn();
Container.SetFlag(BaseEntity.Flags.Reserved5, true, true);
Container.CancelInvoke(Container.Decay);
CreateMarker(Barricade, Killer);
}
private Item CreatedItem(Configuration.Settings.ItemList Reward) {
Item CreateItem = ItemManager.CreateByName(Reward.Shortname, UnityEngine.Random.Range(Reward.AmountMin, Reward.AmountMax), Reward.SkinID);
if (!String.IsNullOrWhiteSpace(Reward.DisplayName)) CreateItem.name = Reward.DisplayName;
return CreateItem;
}
#endregion
private void CheckHeadItemsCooldown() {
if (PrePlayerHeads.Count == 0) return;
foreach(var Task in PrePlayerHeads) {
if (!Task.Value.RewardList.ContainsKey(Task.Key) || Task.Value.RewardList[Task.Key].Count == 0) continue;
if(!IsCooldown(Task.Value.CooldownItem)) {
DistributionReturnedItems(Task.Value, true);
BasePlayer OwnerPlayer = BasePlayer.FindByID(Task.Key);
if (OwnerPlayer == null) return;
ReturnedItems(OwnerPlayer, true);
NextTick(() => {
PrePlayerHeads.Remove(Task.Key);
}
);
}
}
}
private void CheckHeadsCooldown() {
if (PlayerHeads.Count == 0) return;
for(Int32 HeadCount = 0; HeadCount < PlayerHeads.Count; HeadCount++) {
HeadTask Task = PlayerHeads[HeadCount];
if(!IsCooldown(Task)) {
foreach (BasePlayer player in BasePlayer.allPlayerList) SendChat(player, GetLang("CHAT_ALERT_COOLDOWNS_FALSE", player.UserIDString, Task.WantedName));
DistributionReturnedItems(Task);
PlayerHeads.Remove(Task);
BasePlayer Wanted = BasePlayer.FindByID(Task.WantedID);
if (Wanted != null) {
CuiHelper.DestroyUi(Wanted, ALERT_UI);
if (MapMarkers.ContainsKey(Wanted)) UnityEngine.Object.Destroy(MapMarkers[Wanted]);
}
}
}
}
private Boolean IsCooldown(HeadTask Task) => (Task.Cooldown - CurrentTime()) > 0;
private Boolean IsCooldown(Double Cooldown) => (Cooldown - CurrentTime()) > 0;
#endregion
#region Returned Item
private void DistributionReturnedItems(HeadTask Task, Boolean IsPreCreated = false) {
foreach (KeyValuePair<UInt64, List<Configuration.Settings.ItemList>> Rewards in Task.RewardList.Where(Rewards => !DistributionPlayerReturned.ContainsKey(Rewards.Key))) {
DistributionPlayerReturned.Add(Rewards.Key, Rewards.Value);
BasePlayer player = BasePlayer.FindByID(Rewards.Key);
if (player != null) {
SendChat(player, GetLang(!IsPreCreated ? "CHAT_ALERT_RETURNED_ITEMS" : "CHAT_ALERT_RETURNED_ITEMS_COOLDOWN_PRE_CREATED", player.UserIDString));
}
}
}
private void ReturnedItems(BasePlayer player, Boolean IsPreCreated = false) {
if (player == null || !DistributionPlayerReturned.ContainsKey(player.userID)) return;
foreach(Configuration.Settings.ItemList Item in DistributionPlayerReturned[player.userID]) {
Item ItemReturned = CreatedItem(Item);
player.GiveItem(ItemReturned, BaseEntity.GiveItemReason.Generic);
}
DistributionPlayerReturned.Remove(player.userID);
CuiHelper.DestroyUi(player, "IQHEADREWARD_PANEL");
if (!IsPreCreated) SendChat(player, GetLang("CHAT_ALERT_RETURNED_ITEMS_FINISH", player.UserIDString));
}
#endregion
#region Killed Task
private void KilledTask(BasePlayer Killer, BasePlayer Wanted) {
if (!PlayerHeads.Exists(h => h.WantedID == Wanted.userID)) return;
HeadTask Task = PlayerHeads.First(h => h.WantedID == Wanted.userID);
RewardCreated(Task.RewardList.SelectMany(x => x.Value).ToList(), Killer);
PlayerHeads.Remove(Task);
CuiHelper.DestroyUi(Wanted, ALERT_UI);
if (MapMarkers.ContainsKey(Wanted)) UnityEngine.Object.Destroy(MapMarkers[Wanted]);
Interface.Oxide.CallHook("KilledTask", Killer, Wanted);
}
#endregion
#region Created Task
private void CreatedTask(BasePlayer player) {
if (player == null) return;
if (!PrePlayerHeads.ContainsKey(player.userID)) return;
HeadTask Task = PrePlayerHeads[player.userID];
if (!PlayerHeads.Exists(x => x.WantedID == Task.WantedID)) {
PlayerHeadAlert(Task.WantedID, TypeTask.New);
SendChat(player, GetLang("CHAT_CREATED_TASK_RESULT", player.UserIDString, FormatTime(TimeSpan.FromSeconds(Task.Cooldown), player.UserIDString)));
Task.Cooldown += CurrentTime();
PlayerHeads.Add(Task);
Interface.Oxide.CallHook("TaskCreated", player, Task.WantedID);
}
else {
HeadTask ExistsTask = PlayerHeads.FirstOrDefault(x => x.WantedID == Task.WantedID);
if (ExistsTask == null) {
PlayerHeadAlert(Task.WantedID, TypeTask.New);
SendChat(player, GetLang("CHAT_CREATED_TASK_RESULT", player.UserIDString, FormatTime(TimeSpan.FromSeconds(Task.Cooldown), player.UserIDString)));
Task.Cooldown += CurrentTime();
PlayerHeads.Add(Task);
Interface.Oxide.CallHook("TaskCreated", player, Task.WantedID);
}
else {
if (ExistsTask.RewardList.ContainsKey(player.userID)) ExistsTask.RewardList[player.userID] = ExistsTask.RewardList[player.userID].Concat(Task.RewardList[player.userID]).ToList();
else ExistsTask.RewardList.Add(player.userID, Task.RewardList[player.userID]);
var Time = config.Setting.CustomCreatedSetting.TimeSetting.CustomTimeSettings.FirstOrDefault(t => t.Time == Task.Cooldown);
if (Time != null && Time.IQEconomic_CustomTime) {
IQEconomicRemoveBalance(player.userID, Time.IQEconomic_Balance);
ExistsTask.Cooldown += Time.Time;
SendChat(player, GetLang("CHAT_CREATED_TASK_RESULT_MORE_ITEMS_ADD_PLUS_TIME", player.UserIDString, FormatTime(TimeSpan.FromSeconds(ExistsTask.Cooldown - CurrentTime()), player.UserIDString)));
}
else SendChat(player, GetLang("CHAT_CREATED_TASK_RESULT_MORE_ITEMS_ADD", player.UserIDString));
PlayerHeadAlert(Task.WantedID, TypeTask.Retry);
Interface.Oxide.CallHook("UpdateTask", player, Task.WantedID);
}
}
BasePlayer Wanted = BasePlayer.FindByID(Task.WantedID);
if (Wanted != null) CreateMarker(Wanted);
else CreateMarker(BasePlayer.allPlayerList.First(b => b.userID == Task.WantedID));
CuiHelper.DestroyUi(player, "IQHEADREWARD_PANEL");
PrePlayerHeads.Remove(player.userID);
if (Wanted != null) {
TeamControllerAdd(Wanted);
AlertUI(Wanted);
if (config.Setting.UseAlertHead) foreach (BasePlayer allP in BasePlayer.activePlayerList) SendChat(allP, GetLang("NEW_HEAD", allP.UserIDString, Wanted.displayName));
}
}
private void PlayerHeadAlert(UInt64 WantedID, TypeTask typeTask) {
BasePlayer wanted = BasePlayer.FindByID(WantedID);
if (wanted == null) return;
switch(typeTask) {
case TypeTask.New : {
if (config.Setting.AlertUISetting.UseAlertUI) AlertUI(wanted);
SendChat(wanted, GetLang("CHAT_ALERT_TASK_PLAYER", wanted.UserIDString));
break;
}
case TypeTask.Retry : {
SendChat(wanted, GetLang("CHAT_ALERT_TASK_PLAYER_RETRY", wanted.UserIDString));
break;
}
}
}
#endregion
#region Metods Items
private enum TypeCreatedTask {
TakePlayer, TakeItem, TakeTime
}
private void LocalCreatedTask(TypeCreatedTask TypeCreatedTask, UInt64 OwnerID, Item ItemTake = null, Int32 Amount = 0, UInt64 WantedID = 0, Int32 Cooldown = 0) {
BasePlayer player = BasePlayer.FindByID(OwnerID);
if (player == null) return;
if (!PrePlayerHeads.ContainsKey(OwnerID)) PrePlayerHeads.Add(OwnerID, new HeadTask {
Cooldown = 0, WantedID = 0, RewardList = new Dictionary<ulong, List<Configuration.Settings.ItemList>> {
}
}
);
var Data = PrePlayerHeads[OwnerID];
if (!Data.RewardList.ContainsKey(OwnerID)) Data.RewardList.Add(OwnerID, new List<Configuration.Settings.ItemList> {
}
);
if (Cooldown != 0 && Data.Cooldown == 0) Data.Cooldown = Cooldown;
switch (TypeCreatedTask) {
case TypeCreatedTask.TakePlayer : {
Data.WantedID = WantedID;
BasePlayer Wanted = BasePlayer.FindByID(WantedID);
if (Wanted != null) Data.WantedName = Wanted.displayName;
Take_Reward_Items(player);
break;
}
case TypeCreatedTask.TakeItem : {
if (Amount <= 0 || Amount > ItemTake.amount) return;
Data.RewardList[OwnerID].Add(new Configuration.Settings.ItemList {
DisplayName = ItemTake.name, AmountMin = Amount, AmountMax = Amount, Command = String.Empty, IQEconomic = new Configuration.Settings.ItemList.IQEconomics {
MaxBalance = 0, MinBalance = 0,
}
, Shortname = ItemTake.info.shortname, SkinID = ItemTake.skin, TypeRewards = TypeReward.Item,
}
);
player.inventory.Take(null, ItemTake.info.itemid, Amount);
Take_Reward_Items(player);
if (config.Setting.CustomCreatedSetting.ReturnCreated.UseReturnTimer) Data.CooldownItem = config.Setting.CustomCreatedSetting.ReturnCreated.Time;
break;
}
case TypeCreatedTask.TakeTime : {
Data.Cooldown = Cooldown;
break;
}
}
Update_Task(player);
}
private void LocalTaskRemoveItem(BasePlayer player, Item ItemTake) {
var Data = PrePlayerHeads[player.userID];
var DataItem = Data.RewardList[player.userID].FirstOrDefault(x => x.Shortname == ItemTake.info.shortname && x.SkinID == ItemTake.skin && x.AmountMax == ItemTake.amount);
if (DataItem == null) return;
Data.RewardList[player.userID].Remove(DataItem);
player.GiveItem(ItemTake, BaseEntity.GiveItemReason.Generic);
Take_Reward_Items(player);
Update_Task(player);
}
#endregion
#region Metods ReHead
private void ReheadPlayer(BasePlayer player, UInt64 WantedID) {
HeadTask ActiveTask = PlayerHeads.FirstOrDefault(h => h.WantedID == WantedID);
if (ActiveTask == null) return;
Created_Head_Task(player, true);
LocalCreatedTask(TypeCreatedTask.TakePlayer, player.userID, WantedID : WantedID);
Take_Reward_Items(player);
}
#endregion
#region Utilites
private IEnumerator DownloadImages() {
foreach (ItemDefinition Item in ItemManager.itemList) {
String Shortname = Item.shortname;
if (Shortname == "rhib" || Shortname == "vehicle.chassis" || Shortname == "vehicle.module") continue;
String PngKey = $"{Shortname}_64px";
if (!HasImage(PngKey)) AddImage($"http://api.skyplugins.ru/api/getimage/{Shortname}/64", PngKey);
// ... [Code preview truncated due to length. Full source in attached file] ...