C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using Enumerable = System.Linq.Enumerable;
using System.Collections.Generic;
using System.Collections;
using Oxide.Plugins.XDShopExtensionMethods;
using Oxide.Game.Rust.Cui;
using Facepunch;
using Oxide.Core;
using System;
using UnityEngine.Networking;
using UnityEngine;
using System.Text;
using UnityEngine.UI;
using Newtonsoft.Json;
using Oxide.Core.Plugins;
namespace Oxide.Plugins {
[Info("XDShop", "Forum: https://topplugin.ru/ Ds: alone_sempai", "1.4.4")]
[Description("Large easily customizable store")]
class XDShop : RustPlugin {
private void Unload() {
SaveLimits();
SaveCooldowns();
SavePlayerData();
foreach (BasePlayer player in BasePlayer.activePlayerList) CuiHelper.DestroyUi(player, MainLayer);
if (_imageUI != null) {
_imageUI.UnloadImages();
_imageUI = null;
}
StringBuilderInstance = null;
_instance = null;
}
private static XDShop _instance;
private const string NotificationMain = "NOTIFICATION_MAIN";
private const string PanelProduct = "MAIN_PANEL_PRODUCTS";
private void CheckingProducts() {
foreach (Configuration.CategoryShop category in _config.product) {
foreach (Configuration.CategoryShop.Product product in category.product) {
if (product.ID == 0) product.ID = Core.Random.Range(int.MinValue, int.MaxValue);
if (product.Type is ItemType.Item or ItemType.Blueprint or ItemType.CustomItem) {
product.Definition = ItemManager.FindItemDefinition(product.ShortName);
if (product.Definition == null) {
product.ItemsError = true;
PrintError(GetLang("XDSHOP_SERVICE_CONFIG_1", args : product.ID));
continue;
}
}
if (product.Price <= 0 && product.PriceSales <= 0) {
product.ItemsError = true;
PrintError(GetLang("XDSHOP_SERVICE_CONFIG_2", args : product.ID));
}
}
}
}
private const string PageProducts = "PAGE_PRODUCTS";
private void CheckOnDuplicates() {
HashSet<int> itemsSeen = new();
foreach (Configuration.CategoryShop item in _config.product) foreach (Configuration.CategoryShop.Product items in item.product) if (!itemsSeen.Add(items.ID)) {
items.ID = Core.Random.Range(int.MinValue, int.MaxValue);
}
}
private const string ConfirmationsPanelSelling = "CONFIRMATIONS_PANEL_SELLING";
private void SaveLimits() {
Interface.Oxide.DataFileSystem.WriteObject($"{Name}/Player_Limits", _playerDataLimits);
}
private class CooldownData {
public DateTime Buy = new(1970, 1, 1, 0, 0, 0);
public DateTime Sell = new(1970, 1, 1, 0, 0, 0);
}
private const string ConfirmationsPanel = "CONFIRMATIONS_PANEL";
private readonly Dictionary<string, ItemDisplayName> _itemName = new Dictionary<string, ItemDisplayName>();
private Dictionary<ulong, ThemeType> _playerThemeSelect = new();
private void Selling(BasePlayer player, int itemId, int category, int amount, ThemeType themetype) {
Configuration.CategoryShop.Product product = GetCategories(player)[category].product.Find(x => x.ID == itemId);
if (product == null) return;
if (IsDuel(player.userID.Get())) {
NotificationUI(player, NotificationType.Error, GetLang("XDSHOP_UI_NOTIFICATION_SELL_IS_DUEL", player.UserIDString));
return;
}
if (_config.mainSettings.RaidBlock && IsRaid(player)) {
NotificationUI(player, NotificationType.Error, GetLang("XDSHOP_UI_NOTIFICATION_IS_RAID", player.UserIDString));
return;
}
Item[] playerItems = Enumerable.ToArray(Enumerable.Concat(player.inventory.containerMain?.itemList ?? Enumerable.Empty<Item>(), Enumerable.Concat(player.inventory.containerBelt?.itemList ?? Enumerable.Empty<Item>(), player.inventory.containerWear?.itemList ?? Enumerable.Empty<Item>())));
int needAmount = product.AmountSales * amount;
bool blueprint = product.Type == ItemType.Blueprint;
if (blueprint || product.Type == ItemType.CustomItem || product.Type == ItemType.Item) {
if (GetItemAmount(playerItems, product.ShortName, product.SkinID, blueprint) < needAmount) {
NotificationUI(player, NotificationType.Warning, GetLang("XDSHOP_UI_NOTIFICATION_NOT_ENOUGH_ITEM", player.UserIDString));
return;
}
}
float price = product.PriceSales * amount;
if (product.SellCooldown > 0) {
int cooldown = GetCooldownTime(player.userID.Get(), product, false);
if (cooldown > 0) {
NotificationUI(player, NotificationType.Warning, GetLang("XDSHOP_UI_NOTIFICATION_SELL_RECHARGE", player.UserIDString, product.GetProductName(player.UserIDString), TimeHelper.FormatTime(TimeSpan.FromSeconds(cooldown), 5, lang.GetLanguage(player.UserIDString))));
return;
}
SetCooldown(player, product, false);
}
int limit = GetLimit(player, product, false);
if (limit != -1) {
if (limit == 0) {
NotificationUI(player, NotificationType.Warning, GetLang("XDSHOP_UI_NOTIFICATION_SELL_LIMIT", player.UserIDString, product.GetProductName(player.UserIDString)));
return;
}
else if (amount > limit) {
NotificationUI(player, NotificationType.Warning, GetLang("XDSHOP_UI_NOTIFICATION_SELL_LIMIT_1", player.UserIDString, product.GetProductName(player.UserIDString), limit));
return;
}
AddLimit(player, product, amount, false);
}
switch (_config.economicsCustomization.TypeEconomic) {
case EconomicsType.Economics : if ((bool)Economics?.Call("Deposit", player.userID.Get(), (double)price)) {
TakeItem(playerItems, product.ShortName, needAmount, product.SkinID, blueprint);
UpdateBalance(player, themetype);
NotificationUI(player, NotificationType.Success, GetLang("XDSHOP_UI_NOTIFICATION_SUCCESSFUL_SALE", player.UserIDString, product.GetProductName(player.UserIDString)));
}
break;
case EconomicsType.ServerRewards : if (ServerRewards?.Call<object>("AddPoints", player.userID.Get(), (int)price) != null) {
TakeItem(playerItems, product.ShortName, needAmount, product.SkinID, blueprint);
UpdateBalance(player, themetype);
NotificationUI(player, NotificationType.Success, GetLang("XDSHOP_UI_NOTIFICATION_SUCCESSFUL_SALE", player.UserIDString, product.GetProductName(player.UserIDString)));
}
break;
case EconomicsType.IQEconomic : IQEconomic?.Call("API_SET_BALANCE", player.userID.Get(), (int)price);
TakeItem(playerItems, product.ShortName, needAmount, product.SkinID, blueprint);
UpdateBalance(player, themetype);
NotificationUI(player, NotificationType.Success, GetLang("XDSHOP_UI_NOTIFICATION_SUCCESSFUL_SALE", player.UserIDString, product.GetProductName(player.UserIDString)));
break;
case EconomicsType.Item : Item item = ItemManager.CreateByName(_config.economicsCustomization.EconomicShortname, (int)price, _config.economicsCustomization.EconomicSkinId);
player.GiveItem(item, BaseEntity.GiveItemReason.PickedUp);
TakeItem(playerItems, product.ShortName, needAmount, product.SkinID, blueprint);
UpdateBalance(player, themetype);
NotificationUI(player, NotificationType.Success, GetLang("XDSHOP_UI_NOTIFICATION_SUCCESSFUL_SALE", player.UserIDString, product.GetProductName(player.UserIDString)));
break;
}
}
private string GetLang(string langKey, string userID = null, params object[] args) {
StringBuilderInstance.Clear();
if (args == null) return lang.GetMessage(langKey, this, userID);
StringBuilderInstance.AppendFormat(lang.GetMessage(langKey, this, userID), args);
return StringBuilderInstance.ToString();
}
private List<int> GetStacks(ItemDefinition items, int amount) {
List<int> list = new List<int>();
int maxStack = items.stackable;
while (amount > maxStack) {
amount -= maxStack;
list.Add(maxStack);
}
list.Add(amount);
return list;
}
private void LoadData() {
try {
_playerDataCooldowns = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<ulong, PlayerCooldown>>($"{Name}/Player_Cooldowns");
_playerDataLimits = Interface.Oxide.DataFileSystem.ReadObject<PlayerLimits>($"{Name}/Player_Limits");
_playerThemeSelect = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<ulong, ThemeType>>($"{Name}/Players");
}
catch (Exception e) {
PrintError(e.ToString());
}
if (_playerDataCooldowns == null) _playerDataCooldowns = new Dictionary<ulong, PlayerCooldown>();
if (_playerDataLimits == null) _playerDataLimits = new PlayerLimits();
if (_playerThemeSelect == null) _playerThemeSelect = new Dictionary<ulong, ThemeType>();
}
private static void TakeItem(Item[] playerItems, string shortname, int amount, ulong skinid = 0, bool blueprint = false) {
List<Item> acceptedItems = Pool.GetList<Item>();
int itemAmount = 0;
foreach (Item item in playerItems.Where(x => x != null && (blueprint ? x.blueprintTargetDef?.shortname == shortname : x.info?.shortname == shortname) && (skinid == 0 || x.skin == skinid))) {
if (item.isBroken || item.hasCondition && item.condition < item.info.condition.max) continue;
acceptedItems.Add(item);
itemAmount += item.amount;
}
foreach (Item use in acceptedItems) {
if (use.amount == amount) {
use.RemoveFromContainer();
use.Remove();
amount = 0;
break;
}
if (use.amount > amount) {
use.MarkDirty();
use.amount -= amount;
amount = 0;
break;
}
if (use.amount < amount) {
amount -= use.amount;
use.RemoveFromContainer();
use.Remove();
}
}
Pool.FreeList(ref acceptedItems);
}
private void UICATEGORY(BasePlayer player, ThemeType themetype, int page = 0, int categoryIndex = 0) {
Configuration.InterfaceSettings.ThemeCustomization theme = themetype == ThemeType.Dark ? _config.interfaceSettings.DarkTheme : _config.interfaceSettings.LightTheme;
CuiElementContainer container = new CuiElementContainer {
{
new CuiPanel {
CursorEnabled = false, Image = {
Color = "1 1 1 0"
}
, RectTransform = {
AnchorMin = "0.5 1", AnchorMax = "0.5 1", OffsetMin = "-425.607 -77.449", OffsetMax = "454.613 -46.751"
}
}
, PanelProduct, CategoryLayer
}
}
;
int i = 0, catIndex = page * 6;
List<Configuration.CategoryShop> category = GetCategories(player);
foreach (Configuration.CategoryShop cat in category.Page(page, 6)) {
bool thisCat = catIndex == categoryIndex;
string colorLine = thisCat ? theme.color2 : theme.color3;
container.Add(new CuiElement {
Name = $"CATEGORY_{i}", Parent = CategoryLayer, Components = {
new CuiRawImageComponent {
Color = colorLine, Png = _imageUI.GetImage("18")
}
, new CuiRectTransformComponent {
AnchorMin = "0 0.5", AnchorMax = "0 0.5", OffsetMin = $"{0.912 + (i * 133)} -13.949", OffsetMax = $"{95.559 + (i * 133)} 5.349"
}
}
}
);
container.Add(new CuiPanel {
CursorEnabled = false, Image = {
Color = colorLine, Material = "assets/content/ui/uibackgroundblur-ingamemenu.mat"
}
, RectTransform = {
AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5", OffsetMin = "-47.324 -9.649", OffsetMax = "47.324 -8.649"
}
}
, $"CATEGORY_{i}", "CATEGORY_LINE");
container.Add(new CuiButton {
Button = {
Command = thisCat ? "" : $"UI_HandlerShop CHANGE_CATEGORY {page} {catIndex} {themetype}", Color = "0 0 0 0"
}
, Text = {
Text = cat.CategoryName, Font = thisCat ? "robotocondensed-bold.ttf" : "robotocondensed-regular.ttf", FontSize = 12, Align = TextAnchor.UpperCenter, Color = thisCat ? theme.colortext3 : theme.colortext4
}
, RectTransform = {
AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5", OffsetMin = "-47.323 -9.649", OffsetMax = "47.323 9.649"
}
}
, $"CATEGORY_{i}");
catIndex++;
if (i >= 5) break;
i++;
}
if (category.Count > 6) {
container.Add(new CuiPanel {
Image = {
Color = "1 1 1 0"
}
, RectTransform = {
AnchorMin = "1 1", AnchorMax = "1 1", OffsetMin = "-77.294 -30.698", OffsetMax = "0 0"
}
}
, CategoryLayer, "CATEGORY_PAGE");
container.Add(new CuiLabel {
RectTransform = {
AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5", OffsetMin = "-10.74 -6.965", OffsetMax = "10.74 6.965"
}
, Text = {
Text = $"{page + 1}", Font = "robotocondensed-regular.ttf", FontSize = 10, Align = TextAnchor.MiddleCenter, Color = theme.colortext1
}
,
}
, "CATEGORY_PAGE");
if (page > 0) {
container.Add(new CuiElement {
Name = "PAGE_LEFT", Parent = "CATEGORY_PAGE", Components = {
new CuiRawImageComponent {
Color = theme.color1, Png = _imageUI.GetImage("3")
}
, new CuiRectTransformComponent {
AnchorMin = "0 0.5", AnchorMax = "0 0.5", OffsetMin = "13 -6.31", OffsetMax = "20 4.69"
}
}
}
);
container.Add(new CuiButton {
RectTransform = {
AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5", OffsetMin = "-38.647 -15.349", OffsetMax = "0 15.349"
}
, Button = {
Command = $"UI_HandlerShop PAGE_CATEGORY {page - 1} {themetype} {(page - 1) * 6}", Color = "0 0 0 0"
}
, Text = {
Text = ""
}
}
, "CATEGORY_PAGE", "PAGE_LEFT_BTN");
}
if (page + 1 < (int)Math.Ceiling((double)category.Count / 6)) {
container.Add(new CuiElement {
Name = "PAGE_RIGHTS", Parent = "CATEGORY_PAGE", Components = {
new CuiRawImageComponent {
Color = theme.color1, Png = _imageUI.GetImage("4")
}
, new CuiRectTransformComponent {
AnchorMin = "1 0.5", AnchorMax = "1 0.5", OffsetMin = "-20 -6.31", OffsetMax = "-13 4.69"
}
}
}
);
container.Add(new CuiButton {
RectTransform = {
AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5", OffsetMin = "0 -15.349", OffsetMax = "38.646 15.349"
}
, Button = {
Command = $"UI_HandlerShop PAGE_CATEGORY {page + 1} {themetype} {catIndex}", Color = "0 0 0 0"
}
, Text = {
Text = ""
}
}
, "CATEGORY_PAGE", "PAGE_RIGHT_BTN");
}
}
CuiHelper.DestroyUi(player, CategoryLayer);
CuiHelper.AddUi(player, container);
}
private Dictionary<ulong, PlayerCooldown> _playerDataCooldowns = new Dictionary<ulong, PlayerCooldown>();
public static StringBuilder StringBuilderInstance;
private float GetBalance(BasePlayer player) {
switch (_config.economicsCustomization.TypeEconomic) {
case EconomicsType.Economics : if (!Economics) return 0f;
return (float)Economics?.Call<double>("Balance", player.userID.Get());
case EconomicsType.ServerRewards : if (!ServerRewards) return 0f;
return (int)ServerRewards?.Call("CheckPoints", player.userID.Get());
case EconomicsType.IQEconomic : if (!IQEconomic) return 0f;
return (int)IQEconomic?.Call("API_GET_BALANCE", player.userID.Get());
case EconomicsType.Item : return GetItemAmount(Enumerable.ToArray(Enumerable.Concat(player.inventory.containerMain?.itemList ?? Enumerable.Empty<Item>(), Enumerable.Concat(player.inventory.containerBelt?.itemList ?? Enumerable.Empty<Item>(), player.inventory.containerWear?.itemList ?? Enumerable.Empty<Item>()))), _config.economicsCustomization.EconomicShortname, _config.economicsCustomization.EconomicSkinId);
default : return 0f;
}
}
private void OnLeaveNPC(BasePlayer npc, BasePlayer player) {
if (!_config.humanNpcs.NPCs.ContainsKey(npc.UserIDString)) return;
if (!_humanNpcPlayerOpen.ContainsKey(player.userID.Get())) return;
_humanNpcPlayerOpen.Remove(player.userID.Get());
if (_uiPlayerUseNow.Contains(player.userID.Get())) _uiPlayerUseNow.Remove(player.userID.Get());
CuiHelper.DestroyUi(player, "NOTIFICATION_POLOSA");
CuiHelper.DestroyUi(player, "NOTIFICATION_IMG");
CuiHelper.DestroyUi(player, "NOTIFICATION_TEXT");
CuiHelper.DestroyUi(player, NotificationMain);
CuiHelper.DestroyUi(player, MainLayer);
}
[ConsoleCommand("UI_HandlerShop")]
private void CmdConsoleHandler(ConsoleSystem.Arg args) {
BasePlayer player = args.Player();
if (player == null || !args.HasArgs(1)) return;
switch (args.Args[0]) {
case "PAGE_CATEGORY" : {
int page = int.Parse(args.Args[1]);
ThemeType theme = (ThemeType)Enum.Parse(typeof(ThemeType), args.Args[2]);
int category = int.Parse(args.Args[3]);
UICATEGORY(player, theme, page, category);
UIPRODUCT(player, theme, 0, category);
break;
}
case "CHANGE_CATEGORY" : {
int page = int.Parse(args.Args[1]);
int category = int.Parse(args.Args[2]);
ThemeType theme = (ThemeType)Enum.Parse(typeof(ThemeType), args.Args[3]);
CuiHelper.DestroyUi(player, ConfirmationsPanel);
CuiHelper.DestroyUi(player, ConfirmationsPanelSelling);
UICATEGORY(player, theme, page, category);
UIPRODUCT(player, theme, 0, category);
break;
}
case "PAGE_PRODUCT" : {
int page = int.Parse(args.Args[1]);
int category = int.Parse(args.Args[2]);
ThemeType theme = (ThemeType)Enum.Parse(typeof(ThemeType), args.Args[3]);
CuiHelper.DestroyUi(player, ConfirmationsPanel);
CuiHelper.DestroyUi(player, ConfirmationsPanelSelling);
UIPRODUCT(player, theme, page, category);
break;
}
case "AMOUNT_CHANGE_PLUS" : {
int index = int.Parse(args.Args[1]);
int indexCategory = int.Parse(args.Args[2]);
int amount = int.Parse(args.Args[3]);
ThemeType theme = (ThemeType)Enum.Parse(typeof(ThemeType), args.Args[4]);
int type = int.Parse(args.Args[5]);
if (type == 0) {
CuiHelper.DestroyUi(player, ConfirmationsPanel);
UPDATEAMOUNTUI(player, index, indexCategory, amount + 1, theme);
}
else {
UPDATE_UI_SELLING(player, index, indexCategory, amount + 1, theme);
}
break;
}
case "AMOUNT_CHANGE_MINUS" : {
int index = int.Parse(args.Args[1]);
int indexCategory = int.Parse(args.Args[2]);
int amount = int.Parse(args.Args[3]);
ThemeType theme = (ThemeType)Enum.Parse(typeof(ThemeType), args.Args[4]);
int type = int.Parse(args.Args[5]);
if (type == 0) {
CuiHelper.DestroyUi(player, ConfirmationsPanel);
UPDATEAMOUNTUI(player, index, indexCategory, amount - 1, theme);
}
else {
UPDATE_UI_SELLING(player, index, indexCategory, amount - 1, theme);
}
break;
}
case "AMOUNT_CHANGE_KEYBOARD" : {
int index = int.Parse(args.Args[1]);
int indexCategory = int.Parse(args.Args[2]);
ThemeType theme = (ThemeType)Enum.Parse(typeof(ThemeType), args.Args[3]);
if (!int.TryParse(args.Args[4], out int amount)) amount = 1;
CuiHelper.DestroyUi(player, ConfirmationsPanel);
UPDATEAMOUNTUI(player, index, indexCategory, amount, theme);
break;
}
case "PRODUCT_BUY_CONFIRMATION" : {
int indexItem = int.Parse(args.Args[1]);
int indexCategory = int.Parse(args.Args[2]);
int amount = int.Parse(args.Args[3]);
ThemeType theme = (ThemeType)Enum.Parse(typeof(ThemeType), args.Args[4]);
CuiHelper.DestroyUi(player, ConfirmationsPanelSelling);
CONFIRMATIONSUI(player, indexItem, indexCategory, amount, theme);
break;
}
case "PRODUCT_SALE_CONFIRMATION" : {
int indexItem = int.Parse(args.Args[1]);
int indexCategory = int.Parse(args.Args[2]);
int amount = int.Parse(args.Args[3]);
ThemeType theme = (ThemeType)Enum.Parse(typeof(ThemeType), args.Args[4]);
CuiHelper.DestroyUi(player, ConfirmationsPanel);
CONFIRMATIONSSALEUI(player, indexItem, indexCategory, amount, theme);
break;
}
case "PRODUCT_BUY" : {
int indexItem = int.Parse(args.Args[1]);
int indexCategory = int.Parse(args.Args[2]);
int amount = int.Parse(args.Args[3]);
ThemeType theme = (ThemeType)Enum.Parse(typeof(ThemeType), args.Args[4]);
Purchasing(player, indexItem, indexCategory, amount, theme);
CuiHelper.DestroyUi(player, ConfirmationsPanel);
break;
}
case "PRODUCT_SALE" : {
int itemId = int.Parse(args.Args[1]);
int indexCategory = int.Parse(args.Args[2]);
int amount = int.Parse(args.Args[3]);
ThemeType theme = (ThemeType)Enum.Parse(typeof(ThemeType), args.Args[4]);
Selling(player, itemId, indexCategory, amount, theme);
CuiHelper.DestroyUi(player, ConfirmationsPanelSelling);
break;
}
case "THEME_SWITCH" : {
ThemeType theme = (ThemeType)Enum.Parse(typeof(ThemeType), args.Args[1]);
UIMAIN(player, theme == ThemeType.Dark ? ThemeType.Light : ThemeType.Dark);
_playerThemeSelect[player.userID.Get()] = theme == ThemeType.Dark ? ThemeType.Light : ThemeType.Dark;
break;
}
case "CLOSE_ALL_UI" : {
if (_config.humanNpcs.UseHumanNpcs && _humanNpcPlayerOpen.ContainsKey(player.userID.Get())) _humanNpcPlayerOpen.Remove(player.userID.Get());
if (_uiPlayerUseNow.Contains(player.userID.Get())) _uiPlayerUseNow.Remove(player.userID.Get());
CuiHelper.DestroyUi(player, "NOTIFICATION_POLOSA");
CuiHelper.DestroyUi(player, "NOTIFICATION_IMG");
CuiHelper.DestroyUi(player, "NOTIFICATION_TEXT");
CuiHelper.DestroyUi(player, NotificationMain);
CuiHelper.DestroyUi(player, MainLayer);
break;
}
}
}
private void OnPlayerDisconnected(BasePlayer player, string reason) {
if (_uiPlayerUseNow.Contains(player.userID.Get())) _uiPlayerUseNow.Remove(player.userID.Get());
if (_config.humanNpcs.UseHumanNpcs) if (_humanNpcPlayerOpen.ContainsKey(player.userID.Get())) _humanNpcPlayerOpen.Remove(player.userID.Get());
}
private class ItemDisplayName {
public string ru;
public string en;
public string description;
}
private static class TimeHelper {
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.Days == 0) {
if (time.Seconds != 0 && i < maxSubstr) {
if (!string.IsNullOrEmpty(result)) result += " ";
result += $"{Format(time.Seconds, "с", "с", "с")}";
i++;
}
}
break;
default : 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;
}
private static string Format(int units, string form1, string form2, string form3) {
int 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}";
}
}
private class PlayerLimitData {
[JsonProperty(PropertyName = "Player Limits", ObjectCreationHandling = ObjectCreationHandling.Replace)]
private readonly Dictionary<int, ItemLimitData> _itemsLimits = new Dictionary<int, ItemLimitData>();
public void AddItem(Configuration.CategoryShop.Product item, int lots, bool purchase) {
if (!_itemsLimits.ContainsKey(item.ID)) _itemsLimits.Add(item.ID, new ItemLimitData());
if (purchase) _itemsLimits[item.ID].Buy += lots;
else _itemsLimits[item.ID].Sell += lots;
}
public int GetLimit(Configuration.CategoryShop.Product item, bool purchase) {
ItemLimitData data;
if (_itemsLimits.TryGetValue(item.ID, out data)) return purchase ? data.Buy : data.Sell;
return 0;
}
private class ItemLimitData {
public int Sell;
public int Buy;
}
}
private void Init() {
_instance = this;
SubAndUnSubHumanNpcHook();
LoadData();
foreach (KeyValuePair<string, float> discount in _config.discountStores.DiscountPerm) if (!permission.PermissionExists(discount.Key)) permission.RegisterPermission(discount.Key, this);
foreach (string command in _config.mainSettings.Commands) cmd.AddChatCommand(command, this, nameof(XDShopUI));
}
private void ThemeSwitch(BasePlayer player, ThemeType themetype) {
string img = themetype == ThemeType.Dark ? _imageUI.GetImage("12") : _imageUI.GetImage("11");
CuiElementContainer container = new CuiElementContainer {
new CuiElement {
Name = "THEME_BTN", Parent = PanelProduct, Components = {
new CuiRawImageComponent {
Color = "1 1 1 1", Png = img
}
, new CuiRectTransformComponent {
AnchorMin = "0 0", AnchorMax = "0 0", OffsetMin = "16.5 12.8", OffsetMax = "38.5 25.8"
}
}
}
, {
new CuiButton {
RectTransform = {
AnchorMin = "0 0", AnchorMax = "1 1"
}
, Button = {
Command = $"UI_HandlerShop THEME_SWITCH {themetype}", Color = "0 0 0 0"
}
, Text = {
Text = "",
}
}
, "THEME_BTN"
}
}
;
CuiHelper.DestroyUi(player, "THEME_BTN");
CuiHelper.AddUi(player, container);
}
private string GetImage(string shortname, ulong skin = 0) => (string)ImageLibrary?.Call("GetImage", shortname, skin);
private class PlayerLimits {
[JsonProperty(PropertyName = "List of players", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<ulong, PlayerLimitData> Players = new Dictionary<ulong, PlayerLimitData>();
public static PlayerLimitData GetOrAddPlayer(ulong playerId) {
if (!_instance._playerDataLimits.Players.ContainsKey(playerId)) _instance._playerDataLimits.Players.Add(playerId, new PlayerLimitData());
return _instance._playerDataLimits.Players[playerId];
}
}
[ConsoleCommand("xdshop.yes")]
private void CmdShopItemsRefillYes(ConsoleSystem.Arg arg) {
if (arg.Connection != null && arg.Connection.authLevel <= 0) return;
ulong userId = arg.Connection == null || arg.IsRcon ? 0U : arg.Connection.userid;
if (!_pdpw.Contains(userId)) return;
PrintWarning(GetLang("XDSHOP_SERVICE_CMD_REFILL_YES"));
RefillItems();
_pdpw.Remove(userId);
}
private void OnUseNPC(BasePlayer npc, BasePlayer player) {
if (!_config.humanNpcs.NPCs.ContainsKey(npc.UserIDString) || _humanNpcPlayerOpen.ContainsKey(player.userID.Get())) return;
_humanNpcPlayerOpen.Add(player.userID.Get(), npc.UserIDString);
XDShopUI(player);
}
private static int GetItemAmount(Item[] itemsInput, string shortname, ulong skin, bool blueprint = false) {
List<Item> items = new List<Item>();
foreach (Item item in itemsInput.Where(x => x != null && (blueprint ? x.blueprintTargetDef?.shortname == shortname : x.info?.shortname == shortname) && (skin == 0 || x.skin == skin))) {
if (item.isBroken || item.hasCondition && item.condition < item.info.condition.max) continue;
items.Add(item);
}
return items.Sum(item => item.amount);
}
private const string CategoryLayer = "CATEGORY_LAYER";
private void ValidateConfig() {
foreach (Configuration.CategoryShop category in _config.product) {
foreach (Configuration.CategoryShop.Product product in category.product) {
foreach (KeyValuePair<string, int> buyLimits in product.BuyLimits) if (!permission.PermissionExists(buyLimits.Key)) permission.RegisterPermission(buyLimits.Key, this);
foreach (KeyValuePair<string, int> sellLimits in product.SellLimits) if (!permission.PermissionExists(sellLimits.Key)) permission.RegisterPermission(sellLimits.Key, this);
foreach (KeyValuePair<string, int> buyLimitsWipe in product.BuyLimitsWipe) if (!permission.PermissionExists(buyLimitsWipe.Key)) permission.RegisterPermission(buyLimitsWipe.Key, this);
foreach (KeyValuePair<string, int> sellLimitsWipe in product.SellLimitsWipe) if (!permission.PermissionExists(sellLimitsWipe.Key)) permission.RegisterPermission(sellLimitsWipe.Key, this);
}
if (!permission.PermissionExists(category.PermissionCategory)) permission.RegisterPermission(category.PermissionCategory, this);
}
}
protected override void LoadDefaultConfig() {
_config = new Configuration();
}
private readonly Dictionary<ulong, string> _humanNpcPlayerOpen = new Dictionary<ulong, string>();
private void UIMAIN(BasePlayer player, ThemeType themetype) {
Configuration.InterfaceSettings.ThemeCustomization theme = themetype == ThemeType.Dark ? _config.interfaceSettings.DarkTheme : _config.interfaceSettings.LightTheme;
float discount = GetUserDiscount(player);
CuiElementContainer container = new CuiElementContainer();
container.Add(new CuiElement {
Name = PanelProduct, Parent = MainLayer, Components = {
new CuiRawImageComponent {
Color = theme.colorMainBG, Png = _imageUI.GetImage("0")
}
, new CuiRectTransformComponent {
AnchorMin = "0 0", AnchorMax = "1 1"
}
}
}
);
container.Add(new CuiButton {
Button = {
Color = "0 0 0 0", Command = "UI_HandlerShop CLOSE_ALL_UI"
}
, Text = {
Text = "x", Font = "robotocondensed-bold.ttf", FontSize = 13, Align = TextAnchor.MiddleCenter, Color = theme.CloseBtnColor
}
, RectTransform = {
AnchorMin = "1 1", AnchorMax = "1 1", OffsetMin = "-27.467 -24.554", OffsetMax = "-6.946 -5.983"
}
}
, PanelProduct, "CLOSE_MENU_BTN");
container.Add(new CuiLabel {
RectTransform = {
AnchorMin = "0 1", AnchorMax = "0 1", OffsetMin = "115.291 -40.197", OffsetMax = "248.709 -21.203"
}
, Text = {
Text = GetLang("XDSHOP_UI_TITLE", player.UserIDString), Font = "robotocondensed-regular.ttf", FontSize = 11, Align = TextAnchor.MiddleLeft, Color = theme.colorTextTitle
}
}
, PanelProduct, "LABEL_TITLE");
container.Add(new CuiElement {
Name = "IMAGE_TITLE", Parent = PanelProduct, Components = {
new CuiImageComponent {
Color = theme.colorImgTitle, Png = _imageUI.GetImage("7")
}
, new CuiRectTransformComponent {
AnchorMin = "0 1", AnchorMax = "0 1", OffsetMin = "90.223 -40.197", OffsetMax = "107.083 -23.441"
}
}
}
);
if (_config.discountStores.DiscountPerm.Count != 0) {
container.Add(new CuiPanel {
CursorEnabled = false, Image = {
Color = "1 1 1 0"
}
, RectTransform = {
AnchorMin = "1 1", AnchorMax = "1 1", OffsetMin = "-113.69 -46.75", OffsetMax = "-61.91 -18.068"
}
}
, PanelProduct, "DISCOUNT_INFO");
container.Add(new CuiElement {
Name = "DISCOUNT_IMAGE", Parent = "DISCOUNT_INFO", Components = {
new CuiRawImageComponent {
Color = theme.colorImgDiscount, Png = _imageUI.GetImage("5")
}
, new CuiRectTransformComponent {
AnchorMin = "0 0.5", AnchorMax = "0 0.5", OffsetMin = "3 -7.5", OffsetMax = "18 10.5"
}
}
}
);
container.Add(new CuiLabel {
RectTransform = {
AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5", OffsetMin = "-1.576 -7.5", OffsetMax = "25.89 7.051"
}
, Text = {
Text = $"{discount}%", Font = "robotocondensed-bold.ttf", FontSize = 11, Align = TextAnchor.MiddleLeft, Color = theme.colorTextDiscount
}
}
, "DISCOUNT_INFO", "DISCOUNT");
}
CuiHelper.DestroyUi(player, PanelProduct);
CuiHelper.AddUi(player, container);
UIPRODUCT(player, themetype);
UICATEGORY(player, themetype);
UpdateBalance(player, themetype);
if (_config.interfaceSettings.UseChangeTheme) ThemeSwitch(player, themetype);
}
[ConsoleCommand("xdshop.refill")]
private void CmdShopItemsRefill(ConsoleSystem.Arg arg) {
if (arg.Connection != null && arg.Connection.authLevel <= 0) return;
SendReply(arg, GetLang("XDSHOP_SERVICE_CMD_REFILL"));
ulong userId = arg.Connection == null || arg.IsRcon ? 0U : arg.Connection.userid;
if (_pdpw.Contains(userId)) return;
_pdpw.Add(userId);
timer.In(15, () => {
if (_pdpw.Contains(userId)) _pdpw.Remove(userId);
}
);
}
private PlayerCooldown GetCooldown(ulong player) {
PlayerCooldown cooldown;
return _playerDataCooldowns.TryGetValue(player, out cooldown) ? cooldown : null;
}
private enum NotificationType {
Error, Warning, Success
}
private void UpdateBalance(BasePlayer player, ThemeType themetype) {
Configuration.InterfaceSettings.ThemeCustomization theme = themetype == ThemeType.Dark ? _config.interfaceSettings.DarkTheme : _config.interfaceSettings.LightTheme;
CuiElementContainer container = new CuiElementContainer {
{
new CuiPanel {
CursorEnabled = false, Image = {
Color = "1 1 1 0"
}
, RectTransform = {
AnchorMin = "1 1", AnchorMax = "1 1", OffsetMin = "-208.947 -46.751", OffsetMax = "-113.693 -18.067"
}
}
, PanelProduct, "BALANCE_INFO"
}
, new CuiElement {
Name = "BALANCE_IMAGE", Parent = "BALANCE_INFO", Components = {
new CuiImageComponent {
Color = theme.colorImgBalance, Png = _imageUI.GetImage("6")
}
, new CuiRectTransformComponent {
AnchorMin = "0 0.5", AnchorMax = "0 0.5", OffsetMin = "7.9 -7", OffsetMax = "28.9 7"
}
}
}
, {
new CuiLabel {
RectTransform = {
AnchorMin = "1 0.5", AnchorMax = "1 0.5", OffsetMin = "-61.563 -9.46", OffsetMax = "-0.372 7.46"
}
, Text = {
Text = GetBalance(player).ToString("0.0") + _config.economicsCustomization.PrefixBalance, Font = "robotocondensed-bold.ttf", FontSize = 11, Align = TextAnchor.MiddleLeft, Color = theme.colorTextBalance
}
}
, "BALANCE_INFO", "BALANCE"
}
}
;
CuiHelper.DestroyUi(player, "BALANCE_INFO");
CuiHelper.AddUi(player, container);
}
private readonly List<ulong> _pdpw = new List<ulong>();
private const string ProductsLayer = "PRODUCTS_LAYER";
private readonly List<ulong> _uiPlayerUseNow = new List<ulong>();
private void AddDisplayName() {
webrequest.Enqueue($"http://api.skyplugins.ru/api/getitemlist", "", (code, response) => {
if (code == 200) {
_itemList = JsonConvert.DeserializeObject<List<Items>>(response);
foreach (Items items in _itemList) {
_itemName.Add(items.ShortName, new ItemDisplayName {
ru = items.RUdisplayName, en = items.ENdisplayName, description = ItemManager.FindItemDefinition(items.ShortName)?.displayDescription?.english
}
);
}
}
else {
foreach (ItemDefinition item in ItemManager.itemList) {
_itemName.Add(item?.shortname, new ItemDisplayName {
ru = item.displayName?.english, en = item.displayName?.english, description = item.displayDescription?.english
}
);
}
}
}
, this);
}
protected override void LoadConfig() {
base.LoadConfig();
try {
_config = Config.ReadObject<Configuration>();
if (_config == null) throw new Exception();
SaveConfig();
}
catch {
for (int i = 0; i < 3; i++) PrintError("Configuration file is corrupt! Check your config file at https://jsonlint.com/");
LoadDefaultConfig();
}
ValidateConfig();
CheckOnDuplicates();
SaveConfig();
}
private void OnKillNPC(BasePlayer npc, BasePlayer player) {
if (!_config.humanNpcs.NPCs.ContainsKey(npc.UserIDString)) return;
foreach (KeyValuePair<ulong, string> item in _humanNpcPlayerOpen.Where(x => x.Value == npc.UserIDString)) {
if (!_humanNpcPlayerOpen.ContainsKey(item.Key)) continue;
_humanNpcPlayerOpen.Remove(item.Key);
if (_uiPlayerUseNow.Contains(player.userID.Get())) _uiPlayerUseNow.Remove(player.userID.Get());
CuiHelper.DestroyUi(player, "NOTIFICATION_POLOSA");
CuiHelper.DestroyUi(player, "NOTIFICATION_IMG");
CuiHelper.DestroyUi(player, "NOTIFICATION_TEXT");
CuiHelper.DestroyUi(player, NotificationMain);
CuiHelper.DestroyUi(player, MainLayer);
}
}
private void XDShopUI(BasePlayer player) {
if(!string.IsNullOrWhiteSpace(_config.mainSettings.PermissionUseShop) && !permission.UserHasPermission(player.UserIDString, _config.mainSettings.PermissionUseShop)) {
player.ChatMessage(GetLang("XDSHOP_SERVICE_5", player.UserIDString));
return;
}
if(GetCategories(player).Count == 0) {
player.ChatMessage(GetLang("XDSHOP_SERVICE_6", player.UserIDString));
return;
}
// ... [Code preview truncated due to length. Full source in attached file] ...