Иконка ресурса

FREE shop : 1.1.0 1.1.0

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
 // Requires: GUICreator
#define DEBUG
using ConVar;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Core.Plugins;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using UnityEngine;
using static Oxide.Plugins.GUICreator;
namespace Oxide.Plugins {
    [Info("shop", "OHM", "1.1.0")]
    [Description("The ultimate GUI Shop")]
    internal class shop : RustPlugin {
#region references
        [PluginReference]
        private Plugin ServerRewards, Economics;
        private GUICreator guiCreator;
#endregion references
#region global
        DynamicConfigFile CustomerDataFile;
        CustomerData customerData;
        private static shop PluginInstance = null;
        public shop() {
            PluginInstance = this;
        }
#endregion global
#region classes
        public interface ITrackable {
            string name {
                get;
                set;
            }
            int maxAmount {
                get;
                set;
            }
            int cooldownSeconds {
                get;
                set;
            }
        }
        [JsonObject(MemberSerialization.OptIn)]
        public class Category : ITrackable {
            public enum UI {
                command, mixingTable
            }
            [JsonProperty(PropertyName = "Name")]
            public string name {
                get;
                set;
            }
            [JsonProperty(PropertyName = "Fontsize")]
            public int fontsize {
                get;
                set;
            }
            public string safeName => Regex.Replace(name, @" ", "");
            [JsonProperty(PropertyName = "Category icon url/shortname (recommended size: 60px x 60px, item shortname for item icon)")]
            public string categoryicon {
                get;
                set;
            }
            [JsonProperty(PropertyName = "Permission to craft (if empty, no permission required)")]
            public string permission {
                get;
                set;
            }
            [JsonProperty(PropertyName = "Missing Permission Message")]
            public string forbiddenMsg {
                get;
                set;
            }
            [JsonProperty(PropertyName = "Maximum amount items that can be purchased from this category")]
            public int maxAmount {
                get;
                set;
            }
            [JsonProperty(PropertyName = "Cooldown in seconds after buying an item from this category")]
            public int cooldownSeconds {
                get;
                set;
            }
            [JsonProperty(PropertyName = "UI which this category is displayed on (command / mixingTable)")]
            [JsonConverter(typeof(StringEnumConverter))]
            public UI Ui {
                get;
                set;
            }
            = UI.command;
            [JsonProperty(PropertyName = "Products")]
            public List<Product> products {
                get;
                set;
            }
            = new List<Product>();
        }
        [JsonObject(MemberSerialization.OptIn)]
        public class Product : ITrackable {
            [JsonProperty(PropertyName = "Name")]
            public string name {
                get;
                set;
            }
            [JsonProperty(PropertyName = "Fontsize")]
            public int fontsize {
                get;
                set;
            }
            public string safeName => $"{Regex.Replace(name, @" ", "")}_{imageUrl}";
            [JsonProperty(PropertyName = "Description (max.200 characters)")]
            public string description {
                get;
                set;
            }
            = null;
            [JsonProperty(PropertyName = "Image URL (recommended size: 400px x 400px)")]
            public string imageUrl {
                get;
                set;
            }
            [JsonProperty(PropertyName = "Permission to craft (if empty, no permission required)")]
            public string permission {
                get;
                set;
            }
            [JsonProperty(PropertyName = "Missing Permission Message")]
            public string forbiddenMsg {
                get;
                set;
            }
            [JsonProperty(PropertyName = "Maximum amount that can be purchased")]
            public int maxAmount {
                get;
                set;
            }
            [JsonProperty(PropertyName = "Cooldown in seconds after purchase")]
            public int cooldownSeconds {
                get;
                set;
            }
            [JsonProperty(PropertyName = "Command to be executed on purchase")]
            public string command {
                get;
                set;
            }
            [JsonProperty(PropertyName = "Item shortname")]
            public string shortname {
                get;
                set;
            }
            [JsonProperty(PropertyName = "Item amount")]
            public int amount {
                get;
                set;
            }
            [JsonProperty(PropertyName = "Ingredients (max.4)")]
            public Dictionary<string, int> ingredients {
                get;
                set;
            }
            = new Dictionary<string, int>();
        }
        public class Tracker {
            public string name;
            public DateTime lastPurchase;
            public int totalAmount;
            public Tracker() {
            }
        }
#endregion classes
#region oxide hooks
        private void Init() {
            //permissions
            permission.RegisterPermission("shop.use", this);
            permission.RegisterPermission("shop.free", this);
            //Data
            CustomerDataFile = Interface.Oxide.DataFileSystem.GetFile("shop/customerData");
            loadData();
            //Localization
            lang.RegisterMessages(messages, this);
        }
        private void OnServerInitialized() {
#if DEBUG
            Puts("initializing Commands");
#endif
            //commands
            cmd.AddChatCommand(config.command, this, nameof(shopCommand));
            cmd.AddChatCommand("wipeshop", this, nameof(wipeShopCommand));
            cmd.AddConsoleCommand("shop.close", this, nameof(closeShop));
            cmd.AddConsoleCommand("shop.defaultconfig", this, nameof(defaultConfigCommand));
#if DEBUG
            Puts("initialized Commands");
#endif
            //references
            guiCreator = (GUICreator)Manager.GetPlugin("GUICreator");
            if (config.useServerRewards && ServerRewards == null) Puts("ServerRewards not loaded! get it at https://umod.org/plugins/server-rewards");
            if ((config.useServerRewards || config.useEconomics) && Economics == null) Puts("Economics not loaded! get it at https://umod.org/plugins/economics");
            if (guiCreator == null) {
                Puts("GUICreator missing! This shouldn't happen");
                return;
            }
#if DEBUG
            Puts("initialized References");
#endif
            guiCreator.registerImage(this, "white_cross", "https://i.imgur.com/fbwkYDj.png", imgSizeX : 45, imgSizeY : 45);
            guiCreator.registerImage(this, "dollar_icon", config.currencyIcon, imgSizeX : 35, imgSizeY : 35);
            guiCreator.registerImage(this, "no_permission", config.noPermissionOverlay, imgSizeX : 220, imgSizeY : 300);
            guiCreator.registerImage(this, "cooldown", config.cooldownOverlay, imgSizeX : 220, imgSizeY : 300);
            guiCreator.registerImage(this, "info_background", config.defaultInfoBG, imgSizeX : 384, imgSizeY : 384);
            guiCreator.registerImage(this, "products_background", config.background, imgSizeX : 1371, imgSizeY : 920);
#if DEBUG
            Puts("initialized images");
#endif
            //process category/product data
            ServerMgr.Instance.StartCoroutine(ProcessSellOrders());
        }
        private void CanLootEntity(BasePlayer player, MixingTable mixingTable) {
            SendMixingTableUI(player);
        }
        void OnLootEntityEnd(BasePlayer player, MixingTable mixingTable) {
            CloseMixingTableUI(player);
        }
#endregion oxide hooks
#region UI
#region global parameters
        private int maxProducts = 18;
        private int maxIngredients = 4;
        private float FadeIn = 0.1f;
        private float FadeOut = 0.1f;
        private int iconMargin = 5;
        private int productMargin = 10;
        private static GuiColor black40 = new GuiColor(0, 0, 0, 0.4f);
        private static GuiColor black60 = new GuiColor(0, 0, 0, 0.6f);
        private static GuiColor white10 = new GuiColor(1, 1, 1, 0.1f);
        private static GuiColor white30 = new GuiColor(1, 1, 1, 0.3f);
        private static GuiColor white80 = new GuiColor(1, 1, 1, 0.8f);
        private static GuiColor white90 = new GuiColor(1, 1, 1, 0.9f);
        private static GuiColor black90 = new GuiColor(0, 0, 0, 0.9f);
        private static GuiColor green70 = new GuiColor(0, 1, 0, 0.7f);
        private static GuiColor red70 = new GuiColor(1, 0, 0, 0.7f);
        private static GuiColor red90 = new GuiColor(1, 0, 0, 0.9f);
        private static GuiColor halfRed90 = new GuiColor(0.5f, 0, 0, 0.9f);
#endregion global parameters
#region command
        //divide and conquer...private void sendShopUi(BasePlayer player)
        {
            List<Category> categories = getCategories(player);
            sendPanel(player);
            if (config.useEconomics || config.useServerRewards) sendBalance(player);
            sendCategories(player, categories, categories[0]);
            sendProducts(player, categories[0]);
        }
        private void closeShopUi(BasePlayer player) {
            if (player == null) return;
            GuiTracker.getGuiTracker(player).destroyGui(this, "shop");
        }
        private void sendPanel(BasePlayer player) {
            GuiContainer container = new GuiContainer(this, "shop");
            container.addPlainPanel("panel_bgpanel", new Rectangle(60, 40, 1800, 1000, 1920, 1080, true), GuiContainer.Layer.menu, black60, FadeIn, FadeOut, GuiContainer.Blur.medium);
            container.addPlainPanel("categories_productpanel", new Rectangle(65, 95, 1391, 940, 1920, 1080, true), GuiContainer.Layer.menu, black60, FadeIn, FadeOut);
            container.addImage("productpanel_background", new Rectangle(75, 105, 1371, 920, 1920, 1080, true), "products_background", GuiContainer.Layer.menu, white30, FadeIn, FadeOut);
            container.addPanel("balance_panel", new Rectangle(1461, 45, 345, 48, 1920, 1080, true), GuiContainer.Layer.menu, black60, FadeIn, FadeOut);
            //info panel
            container.addPlainPanel("info_bgpanel", new Rectangle(1461, 95, 394, 940, 1920, 1080, true), GuiContainer.Layer.menu, black60, FadeIn, FadeOut);
            container.addPanel("info_imgbackground", new Rectangle(1466, 100, 384, 384, 1920, 1080, true), GuiContainer.Layer.menu, null, FadeIn, FadeOut, null, "info_background");
            container.addPlainPanel("info_labelbackground", new Rectangle(1466, 489, 384, 45, 1920, 1080, true), GuiContainer.Layer.menu, white30, FadeIn, FadeOut);
            container.addPlainPanel("info_descbackground", new Rectangle(1466, 539, 384, 241, 1920, 1080, true), GuiContainer.Layer.menu, white30, FadeIn, FadeOut);
            //ingredients
            for (int i = 0; i < maxIngredients; i++) {
                container.addPlainPanel($"ingredients_icon{i}background", new Rectangle(1466, (785 + (i * 50)), 45, 45, 1920, 1080, true), GuiContainer.Layer.menu, white30, FadeIn, FadeOut);
                container.addPlainPanel($"ingredients_amount{i}background", new Rectangle(1516, (785 + (i * 50)), 95, 45, 1920, 1080, true), GuiContainer.Layer.menu, white30, FadeIn, FadeOut);
                container.addPlainPanel($"ingredients_shortname{i}background", new Rectangle(1616, (785 + (i * 50)), 234, 45, 1920, 1080, true), GuiContainer.Layer.menu, white30, FadeIn, FadeOut);
            }
            container.addPlainPanel("close_bg", new Rectangle(1810, 45, 45, 45, 1920, 1080, true), GuiContainer.Layer.menu, red90, FadeIn, FadeOut);
            container.addButton("close", new Rectangle(1810, 45, 45, 45, 1920, 1080, true), GuiContainer.Layer.menu, null, FadeIn, FadeOut, CursorEnabled : true, imgName : "white_cross");
            container.display(player);
        }
        private void sendBalance(BasePlayer player) {
            GuiContainer container = new GuiContainer(this, "balance", "shop");
            string balanceString = $"Balance: {getPoints(player)}";
            container.addPanel("balance_content", new Rectangle(1461, 45, 345, 48, 1920, 1080, true), GuiContainer.Layer.menu, null, FadeIn, FadeOut);
            container.addImage("balance_img", new Rectangle(1461 + iconMargin, 45 + iconMargin, 45 - (2*iconMargin), 45 - (2*iconMargin), 1920, 1080, true), "dollar_icon", GuiContainer.Layer.menu, null, FadeIn, FadeOut);
            container.addText("balance_text", new Rectangle(1511, 45, 295, 45, 1920, 1080, true), GuiContainer.Layer.menu, new GuiText(balanceString, 22, white90, TextAnchor.MiddleLeft), FadeIn, FadeOut);
            container.display(player);
        }
        private void sendCategories(BasePlayer player, List<Category> categories, Category category) {
            categories = categories.Where(c => c.Ui == Category.UI.command).ToList();
            GuiContainer container = new GuiContainer(this, "categories", "shop");
            int start = 65;
            int gap = 5;
            float sizeEach = (1391 - ((categories.Count - 1) * gap)) / categories.Count;
            for (int i = 0; i < categories.Count; i++) {
                float anchor = start + (i * (sizeEach + gap));
                container.addPlainPanel($"categories_{categories[i].safeName}", new Rectangle((i == 0) ? start : anchor, 45, sizeEach, 48, 1920, 1080, true), GuiContainer.Layer.menu, (category == categories[i]) ? black60 : white30, FadeIn, FadeOut);
                container.addText($"categories_{categories[i].safeName}_text", new Rectangle(((i == 0) ? start : anchor) + 50, 45, sizeEach - 50, 45, 1920, 1080, true), GuiContainer.Layer.menu, new GuiText(categories[i].name.ToUpper(), categories[i].fontsize, (category == categories[i]) ? white90 : black90, TextAnchor.MiddleLeft), FadeIn, FadeOut);
                if(!string.IsNullOrEmpty(categories[i].categoryicon)) {
                    ItemDefinition itemDefinition = ItemManager.FindItemDefinition(categories[i].categoryicon);
                    if(itemDefinition != null) {
                        container.addRawImage($"categories_{categories[i].safeName}_icon", new Rectangle(((i == 0) ? start : anchor) + iconMargin, 45 + iconMargin, 45 - (2*iconMargin), 45 - (2*iconMargin), 1920, 1080, true), guiCreator.getItemIcon(categories[i].categoryicon), GuiContainer.Layer.menu, null, FadeIn, FadeOut);
                    }
                    else {
                        container.addImage($"categories_{categories[i].safeName}_icon", new Rectangle(((i == 0) ? start : anchor) + iconMargin, 45 + iconMargin, 45 - (2 * iconMargin), 45 - (2 * iconMargin), 1920, 1080, true), categories[i].safeName, GuiContainer.Layer.menu, null, FadeIn, FadeOut);
                    }
                }
                Category selected = categories[i];
                Action<BasePlayer, string[]> callback = (bPlayer, input) => {
                    if (category == selected) return;
                    GuiTracker.getGuiTracker(bPlayer).destroyGui(this, "categories");
                    sendCategories(bPlayer, categories, selected);
                    sendProducts(bPlayer, selected);
                }
                ;
                container.addButton($"categories_{categories[i].safeName}_button", new Rectangle((i == 0) ? start : anchor, 45, sizeEach, 48, 1920, 1080, true), GuiContainer.Layer.menu, null, FadeIn, FadeOut, null, callback);
            }
            container.display(player);
        }
        private void sendProducts(BasePlayer player, Category category) {
            GuiContainer container = new GuiContainer(this, "products", "categories");
            List<Product> products = getProducts(player, category);
            int startX = 75;
            int startY = 105;
            int gap = 10;
            int rows = 3;
            int columns = 6;
            float sizeEachX = (1391 - ((columns + 1) * gap)) / columns;
            //220,16 //200
            float sizeEachY = (940 - ((rows + 1) * gap)) / rows;
            //300 //280
            Product activeProduct = null;
            int count = 0;
            for (int i = 0; i < rows; i++) {
                if (count == maxProducts) break;
                if (count == products.Count) break;
                float anchorY = startY + (i * (sizeEachY + gap));
                for (int j = 0; j < columns; j++) {
                    if (count == maxProducts) break;
                    if (count == products.Count) break;
                    Product product = products[count];
                    float anchorX = startX + (j * (sizeEachX + gap));
                    container.addPanel($"products_{product.safeName}_imgbg", new Rectangle((j == 0) ? startX : anchorX, (i == 0) ? startY : anchorY, sizeEachX, sizeEachX, 1920, 1080, true), GuiContainer.Layer.menu, white30, FadeIn, FadeOut);
                    if (string.IsNullOrEmpty(product.imageUrl) && !string.IsNullOrEmpty(product.shortname)) {
                        container.addRawImage($"products_{product.safeName}_img", new Rectangle((j == 0) ? (startX + productMargin) : (anchorX + productMargin), (i == 0) ? (startY + productMargin) : (anchorY + productMargin), sizeEachX - (2 * productMargin), sizeEachX - (2 * productMargin), 1920, 1080, true), guiCreator.getItemIcon(product.shortname), GuiContainer.Layer.menu, null, FadeIn, FadeOut);
                    }
                    else {
                        container.addPanel($"products_{product.safeName}_img", new Rectangle((j == 0) ? (startX + productMargin) : (anchorX + productMargin), (i == 0) ? (startY + productMargin) : (anchorY + productMargin), sizeEachX - (2 * productMargin), sizeEachX - (2 * productMargin), 1920, 1080, true), GuiContainer.Layer.menu, null, FadeIn, FadeOut, null, product.safeName);
                    }
                    int remainingProduct;
                    int remainingCategory;
                    maxAmountReached(player.userID, product, out remainingProduct);
                    maxAmountReached(player.userID, category, out remainingCategory);
                    int remaining = Math.Min(remainingProduct, remainingCategory);
                    if (remaining != 0 && remaining != int.MaxValue) {
                        container.addText($"products_{product.safeName}_amount", new Rectangle((j == 0) ? (startX + productMargin) : (anchorX + productMargin), ((i == 0) ? (startY + productMargin) : (anchorY + productMargin)) + sizeEachX - (2 * productMargin) - 25, sizeEachX - (2 * productMargin), 25, 1920, 1080, true), GuiContainer.Layer.menu, new GuiText($"{remaining} left", 14, white90), FadeIn, FadeOut);
                    }
                    container.addPanel($"products_{product.safeName}_label", new Rectangle((j == 0) ? startX : anchorX, ((i == 0) ? startY : anchorY) + 5 + sizeEachX, sizeEachX, sizeEachY - (5 + sizeEachX), 1920, 1080, true), GuiContainer.Layer.menu, white30, FadeIn, FadeOut, new GuiText(product.name, product.fontsize, black90));
                    int index = count;
                    Action<BasePlayer, string[]> callback = (bPlayer, input) => {
                        if (activeProduct == products[index]) return;
                        GuiTracker.getGuiTracker(bPlayer).destroyGui(this, "info");
                        sendInfo(bPlayer, products[index]);
                        sendCheckout(bPlayer, category, products[index]);
                        activeProduct = products[index];
                    }
                    ;
                    if (!hasPermission(player, category, product) || maxAmountReached(player.userID, category) || maxAmountReached(player.userID, product)) {
                        Rectangle pos = new Rectangle((j == 0) ? startX : anchorX, (i == 0) ? startY : anchorY, sizeEachX, sizeEachX, 1920, 1080, true);
                        container.addPlainPanel($"products_{product.safeName}_forbidden_bgpanel", pos, GuiContainer.Layer.menu, black40, FadeIn, FadeOut, GuiContainer.Blur.medium);
                        container.addImage($"products_{product.safeName}_forbidden", pos, "no_permission", GuiContainer.Layer.menu, white90, FadeIn, FadeOut);
                    }
                    else {
                        int cooldown = 0;
                        if (!cooldownElapsed(player.userID, product, out cooldown)) {
                        }
                        else if (!cooldownElapsed(player.userID, category, out cooldown)) {
                        }
                        if(cooldown > 0) {
                            container.addPlainPanel($"products_{product.safeName}_cooldown_bgpanel", new Rectangle((j == 0) ? startX : anchorX, (i == 0) ? startY : anchorY, sizeEachX, sizeEachX, 1920, 1080, true), GuiContainer.Layer.menu, black40, FadeIn, FadeOut, GuiContainer.Blur.medium);
                            container.addImage($"products_{product.safeName}_cooldown", new Rectangle(), "cooldown", $"products_{product.safeName}_cooldown_bgpanel", white90, FadeIn, FadeOut);
                            container.addText($"products_{product.safeName}_cooldown_text", new Rectangle(), new GuiText(formatTimeSpan(new TimeSpan(0, 0, cooldown)), 14, white90), FadeIn, FadeOut, $"products_{product.safeName}_cooldown");
                        }
                    }
                    container.addPlainButton($"products_{product.safeName}_button", new Rectangle((j == 0) ? startX : anchorX, (i == 0) ? startY : anchorY, sizeEachX, sizeEachY, 1920, 1080, true), GuiContainer.Layer.menu, callback : callback);
                    count++;
                }
            }
            container.display(player);
        }
        private void sendInfo(BasePlayer player, Product product) {
            GuiContainer container = new GuiContainer(this, "info", "categories");
            if (string.IsNullOrEmpty(product.imageUrl) && !string.IsNullOrEmpty(product.shortname)) {
                container.addRawImage("info_img", new Rectangle(1466, 100, 384, 384, 1920, 1080, true), guiCreator.getItemIcon(product.shortname), GuiContainer.Layer.menu, null, FadeIn, FadeOut);
            }
            else {
                container.addPanel("info_img", new Rectangle(1466, 100, 384, 384, 1920, 1080, true), GuiContainer.Layer.menu, null, FadeIn, FadeOut, null, product.safeName);
            }
            container.addText("info_Label", new Rectangle(1466, 489, 384, 45, 1920, 1080, true), GuiContainer.Layer.menu, new GuiText(product.name, 26, black90), FadeIn, FadeOut);
            container.addText("info_Description", new Rectangle(1466, 539, 384, 241, 1920, 1080, true), GuiContainer.Layer.menu, new GuiText(product.description, 14, black90), FadeIn, FadeOut);
            container.display(player);
        }
        private void sendCheckout(BasePlayer player, Category category, Product product, int amount = 1) {
            if (product == null) return;
            GuiContainer container = new GuiContainer(this, "checkout", "info");
            List<Category> categories = getCategories(player);
            Queue<bool> canAffordIngredients;
            bool canAfford = PluginInstance.canAfford(player, product, amount, out canAffordIngredients);
            //ingredients
            int count = 0;
            foreach (KeyValuePair<string, int> ingredient in product.ingredients) {
                if (count == maxIngredients) break;
                bool canAfford_ = canAffordIngredients.Dequeue();
                string displayName;
                ItemDefinition itemDefinition = ItemManager.FindItemDefinition(ingredient.Key);
                if (itemDefinition != null) {
                    displayName = itemDefinition.displayName.english;
                    container.addRawImage($"ingredients_icon{count}", new Rectangle(1468, (787 + (count * 50)), 41, 41, 1920, 1080, true), guiCreator.getItemIcon(itemDefinition.shortname), GuiContainer.Layer.menu, null, 0, 0);
                }
                else {
                    displayName = ingredient.Key;
                    container.addImage($"ingredients_icon{count}", new Rectangle(1466 + iconMargin, (785 + (count * 50)) + iconMargin, 45 - (2*iconMargin), 45 - (2*iconMargin), 1920, 1080, true), "dollar_icon", GuiContainer.Layer.menu, null, 0, 0);
                }
                container.addText($"ingredients_amount{count}", new Rectangle(1516, (785 + (count * 50)), 95, 45, 1920, 1080, true), GuiContainer.Layer.menu, new GuiText((ingredient.Value * amount).ToString(), 20, canAfford_ ? black90 : halfRed90), 0, 0);
                container.addText($"ingredients_shortname{count}", new Rectangle(1616, (785 + (count * 50)), 234, 45, 1920, 1080, true), GuiContainer.Layer.menu, new GuiText(displayName, 20, canAfford_ ? black90 : halfRed90), 0, 0);
                count++;
            }
            //remaining amount
            int remainingProduct;
            int remainingCategory;
            maxAmountReached(player.userID, product, out remainingProduct);
            maxAmountReached(player.userID, category, out remainingCategory);
            int remaining = Math.Min(remainingProduct, remainingCategory);
            int amountLocal = amount;
            //atc
            Action<BasePlayer, string[]> minusCallback = (bPlayer, input) => {
                if (amountLocal == 1) return;
                sendCheckout(bPlayer, category, product, amountLocal - 1);
            }
            ;
            container.addPlainButton("atc_minusbackground", new Rectangle(1466, 985, 45, 45, 1920, 1080, true), GuiContainer.Layer.menu, black60, 0, 0, new GuiText("-", 10, white90), minusCallback);
            container.addPanel("atc_amountbackground", new Rectangle(1516, 985, 45, 45, 1920, 1080, true), GuiContainer.Layer.menu, white30, 0, 0, new GuiText(Math.Max((product.amount*amount), 1).ToString(), 10, black90));
            Action<BasePlayer, string[]> plusCallback = (bPlayer, input) => {
                if (product.amount == 0) return;
                if (amountLocal >= remaining) return;
                sendCheckout(bPlayer, category, product, amountLocal + 1);
            }
            ;
            container.addPlainButton("atc_plusbackground", new Rectangle(1566, 985, 45, 45, 1920, 1080, true), GuiContainer.Layer.menu, black60, 0, 0, new GuiText("+", 10, white90), plusCallback);
            //buy button
            Action<BasePlayer, string[]> buyCallback = (bPlayer, input) => {
                if (purchase(bPlayer, category, product, amount)) {
                    sendCheckout(player, category, product, amount);
                    sendBalance(player);
                }
                sendProducts(player, category);
            }
            ;
            container.addPlainButton("buybutton", new Rectangle(1616, 985, 234, 45, 1920, 1080, true), GuiContainer.Layer.menu, canBuy(player, category, product, amount) ? green70 : red70, 0, 0, new GuiText("Buy", 26, white90), buyCallback);
            container.display(player);
        }
#endregion
#region mixingTable
        private void SendMixingTableUI(BasePlayer player) {
            player.ChatMessage("Sending shop UI");
        }
        private void CloseMixingTableUI(BasePlayer player) {
            player.ChatMessage("Closing shop UI");
        }
#endregion
#endregion UI
#region commands
        private void shopCommand(BasePlayer player, string command, string[] args) {
            if (GuiTracker.getGuiTracker(player).getContainer(this, "shop") != null) {
                closeShopUi(player);
                return;
            }
            if (!permission.UserHasPermission(player.UserIDString, "shop.use")) {
                PrintToChat(player, lang.GetMessage("noPermission", this, player.UserIDString));
                return;
            }
            sendShopUi(player);
        }
        private void closeShop(ConsoleSystem.Arg arg) {
            BasePlayer player = arg.Player();
            if (player == null) return;
            closeShopUi(player);
        }
        private void wipeShopCommand(BasePlayer player, string command, string[] args) {
            if(!player.IsAdmin) {
                PrintToChat(player, lang.GetMessage("noPermission", this, player.UserIDString));
                return;
            }
            customerData.purchaseTrackers.Clear();
            player.ChatMessage("shop data wiped");
            saveData();
        }
#endregion commands
#region transaction
        private bool purchase(BasePlayer player, Category category, Product product, int amount) {
#if DEBUG
            player.ChatMessage($"purchasing {amount} x {product.name}");
#endif
            //can buy?
            if (!hasPermission(player, category, product)) {
                string errorMsg = lang.GetMessage("noPermissionToBuy", this, player.UserIDString);
                if (!string.IsNullOrEmpty(category.forbiddenMsg)) errorMsg = category.forbiddenMsg;
                if (!string.IsNullOrEmpty(product.forbiddenMsg)) errorMsg = product.forbiddenMsg;
                guiCreator.customGameTip(player, errorMsg, 2, gametipType.error);
                return false;
            }
            if (!canAfford(player, product, amount)) {
                guiCreator.customGameTip(player, lang.GetMessage("cantAfford", this, player.UserIDString), 2, gametipType.error);
                return false;
            }
            if(maxAmountReached(player.userID, category) || maxAmountReached(player.userID, product)) {
                guiCreator.customGameTip(player, lang.GetMessage("maxAmount", this, player.UserIDString), 2, gametipType.error);
                return false;
            }
            int cooldown;
            if (!cooldownElapsed(player.userID, product, out cooldown)) {
                string remaining = formatTimeSpan(new TimeSpan(0, 0, cooldown));
                guiCreator.customGameTip(player, string.Format(lang.GetMessage("cooldown", this, player.UserIDString), remaining), 2, gametipType.error);
                return false;
            }
            else if(!cooldownElapsed(player.userID, category, out cooldown)) {
                string remaining = formatTimeSpan(new TimeSpan(0, 0, cooldown));
                guiCreator.customGameTip(player, string.Format(lang.GetMessage("cooldown", this, player.UserIDString), remaining), 2, gametipType.error);
                return false;
            }
            if(!enoughInventorySpace(player, product, amount)) {
                guiCreator.customGameTip(player, string.Format(lang.GetMessage("noSpace", this, player.UserIDString)), 2, gametipType.error);
                return false;
            }
            //take price
            if (!permission.UserHasPermission(player.UserIDString, "shop.free")) {
                foreach (KeyValuePair<string, int> ingredient in product.ingredients) {
                    ItemDefinition itemDefinition = ItemManager.FindItemDefinition(ingredient.Key);
                    if (itemDefinition != null) {
                        player.inventory.Take(null, itemDefinition.itemid, ingredient.Value*amount);
                    }
                    else if (ingredient.Key.ToUpper() == "POINTS" || ingredient.Key.ToUpper() == "RP" || ingredient.Key.ToUpper() == "REWARD POINTS") {
                        takePoints(player, ingredient.Value*amount);
                    }
                }
            }
            //tracker
            if(category.maxAmount != 0 || category.cooldownSeconds != 0) {
                Tracker tracker = getTracker(player.userID, category.name);
                if (tracker == null) tracker = new Tracker {
                    name = category.name
                }
                ;
                tracker.lastPurchase = DateTime.Now;
                if(category.maxAmount != 0) tracker.totalAmount += amount;
                customerData.purchaseTrackers[player.userID].Add(tracker);
                saveData();
            }
            if (product.maxAmount != 0 || product.cooldownSeconds != 0) {
                Tracker tracker = getTracker(player.userID, product.name);
                if (tracker == null) tracker = new Tracker {
                    name = product.name
                }
                ;
                tracker.lastPurchase = DateTime.Now;
                if(product.maxAmount != 0) tracker.totalAmount += amount;
                customerData.purchaseTrackers[player.userID].Add(tracker);
                saveData();
            }
            //result
            if (!string.IsNullOrEmpty(product.command)) {
                //execute command
                string command = Regex.Replace(product.command, @"{steamid}", player.userID.ToString());
                command = Regex.Replace(command, @"{amount}", (product.amount).ToString());
                command = Regex.Replace(command, @"{name}", player.displayName);
                command = Regex.Replace(command, @"{x}", player.transform.position.x.ToString());
                command = Regex.Replace(command, @"{y}", player.transform.position.y.ToString());
                command = Regex.Replace(command, @"{z}", player.transform.position.z.ToString());
                for (int i = 0; i < amount; i++) {
                    Server.Command(command);
                }
                Effect.server.Run("assets/prefabs/deployable/vendingmachine/effects/vending-machine-purchase-human.prefab", player.transform.position);
                log(player, product, amount);
                return true;
            }
            else if (!string.IsNullOrEmpty(product.shortname) && product.amount != 0) {
                //give item
                ItemDefinition itemDefinition = ItemManager.FindItemDefinition(product.shortname);
                if (itemDefinition == null) {
                    Puts($"purchase: shortname {product.shortname} is invalid!");
                    return false;
                }
                //stacksize handling
                int totalAmount = amount * product.amount;
                while (totalAmount > 0) {
                    int stacksize = Math.Min(itemDefinition.stackable, totalAmount);
                    Item item = ItemManager.Create(itemDefinition, stacksize);
                    if (item != null) player.GiveItem(item);
                    totalAmount -= stacksize;
                }
                Effect.server.Run("assets/prefabs/deployable/vendingmachine/effects/vending-machine-purchase-human.prefab", player.transform.position);
                log(player, product, amount);
                return true;
            }
            return false;
        }
#endregion transaction
#region helpers
        private string formatTimeSpan(TimeSpan span) {
            int d = (int)span.TotalDays;
            int h = (int)(span.TotalHours-(d * 24));
            int m = (int)(span.TotalMinutes - (h * 60) - (d * 24 * 60));
            int s = (int)(span.TotalSeconds - (m * 60) - (h * 60 * 60) - (d * 24 * 60 *60));
            StringBuilder sb = new StringBuilder();
            if (d != 0) sb.Append($"{d}d ");
            if (h != 0) sb.Append($"{h}h ");
            if (m != 0) sb.Append($"{m}m ");
            if (s != 0) sb.Append($"{s}s");
            return sb.ToString();
        }
        private void log(BasePlayer player, Product product, int amount) {
            LogToFile("shopPurchases", $"{DateTime.Now.ToString("MM/dd/yyyy HH : mm : ss")} {player.displayName}[{player.userID}] bought {Math.Max(1,product.amount)*amount} x {product.name}" , this);
        }
        private Tracker getTracker(ulong userID, string name) {
            List<Tracker> userTrackers;
            if (!customerData.purchaseTrackers.TryGetValue(userID, out userTrackers)) {
                userTrackers = new List<Tracker>();
                customerData.purchaseTrackers.Add(userID, userTrackers);
                saveData();
            }
            foreach(Tracker tracker in userTrackers) {
                if (tracker.name == name) return tracker;
            }
            return null;
        }
        private bool maxAmountReached(ulong userID, ITrackable input) {
            int temp;
            return maxAmountReached(userID, input, out temp);
        }
        private bool maxAmountReached(ulong userID, ITrackable input, out int remainingAmount) {
            remainingAmount = int.MaxValue;
            if (input.maxAmount == 0) return false;
            remainingAmount = input.maxAmount;
            Tracker tracker = getTracker(userID, input.name);
            if (tracker == null) return false;
            remainingAmount = input.maxAmount - tracker.totalAmount;
#if DEBUG
            BasePlayer.FindByID(userID).ChatMessage($"remainingAmount = {remainingAmount}");
#endif
            if (remainingAmount <= 0) return true;
            return false;
        }
        private bool cooldownElapsed(ulong userID, ITrackable input) {
            int temp;
            return cooldownElapsed(userID, input, out temp);
        }
        private bool cooldownElapsed(ulong userID, ITrackable input, out int remainingSeconds) {
            remainingSeconds = 0;
            Tracker tracker = getTracker(userID, input.name);
            if (tracker == null) return true;
            remainingSeconds = (int)(input.cooldownSeconds - DateTime.Now.Subtract(tracker.lastPurchase).TotalSeconds);
#if DEBUG
            BasePlayer.FindByID(userID).ChatMessage($"remainingSeconds = {remainingSeconds}");
#endif
            if (remainingSeconds <= 0) return true;
            return false;
        }
        private List<Category> getCategories(BasePlayer player) {
            if (!config.hideNonPermission) return config.Categories;
            List<Category> output = new List<Category>();
            foreach (Category category in config.Categories) {
                if (hasPermission(player, category)) output.Add(category);
            }
            return output;
        }
        private List<Product> getProducts(BasePlayer player, Category category) {
            if (!config.hideNonPermission) return category.products;
            if (!hasPermission(player, category)) return null;
            List<Product> output = new List<Product>();
            foreach (Product product in category.products) {
                if (hasPermission(player, category, product)) output.Add(product);
            }
            return output;
        }
        private bool canBuy(BasePlayer player, Category category, Product product, int amount) {
            if(!hasPermission(player, category, product)) return false;
            if (!canAfford(player, product, amount)) return false;
            if (maxAmountReached(player.userID, category)) return false;
            if (maxAmountReached(player.userID, product)) return false;
            if (!cooldownElapsed(player.userID, category)) return false;
            if (!cooldownElapsed(player.userID, product)) return false;
            if (!enoughInventorySpace(player, product, amount)) return false;
            return true;
        }
        private bool enoughInventorySpace(BasePlayer player, Product product, int amount) {
            int freeSlots = 0;
            if(!player.inventory.containerMain.IsFull()) {
                for(int i = 0; i < 24; i++) {
                    if (player.inventory.containerMain.GetSlot(i) == null) freeSlots++;
                }
            }
            if (!player.inventory.containerBelt.IsFull()) {
                for (int i = 0; i < 24; i++) {
                    if (player.inventory.containerBelt.GetSlot(i) == null) freeSlots++;
                }
            }
            if (freeSlots == 0) return false;
            int requiredSlots = amount;
            if(!string.IsNullOrEmpty(product.shortname)) {
                ItemDefinition itemDefinition = ItemManager.FindItemDefinition(product.shortname);
                if(itemDefinition != null) {
                    requiredSlots = (amount * product.amount) / itemDefinition.stackable;
                    if (((amount * product.amount) % itemDefinition.stackable) != 0) requiredSlots++;
                }
            }
            if (requiredSlots > freeSlots) return false;
            return true;
        }
        private bool hasPermission(BasePlayer player, Category category, Product product = null) {
            if (!string.IsNullOrEmpty(category.permission) && !permission.UserHasPermission(player.UserIDString, category.permission)) return false;
            if (product != null) {
                if (!string.IsNullOrEmpty(product.permission) && !permission.UserHasPermission(player.UserIDString, product.permission)) return false;
            }
            return true;
        }
        private bool canAfford(BasePlayer player, Product product, int amount) {
            Queue<bool> temp;
            return canAfford(player, product, amount, out temp);
        }
        private bool canAfford(BasePlayer player, Product product, int amount, out Queue<bool> ingredients) {
            ingredients = new Queue<bool>();
            bool total = true;
            foreach (KeyValuePair<string, int> ingredient in product.ingredients) {
                int balance = 0;
                ItemDefinition itemDefinition = ItemManager.FindItemDefinition(ingredient.Key);
                if (itemDefinition != null) {
                    balance = player.inventory.GetAmount(itemDefinition.itemid);
                }
                else if (ingredient.Key.ToUpper() == "POINTS" || ingredient.Key.ToUpper() == "RP" || ingredient.Key.ToUpper() == "REWARD POINTS") {
                    balance = getPoints(player);
                }
                if (balance < (ingredient.Value * amount)) {
                    total = false;
                    ingredients.Enqueue(false);
                }
                else {
                    ingredients.Enqueue(true);
                }
            }
            return total;
        }
        private int getPoints(BasePlayer player) {
            if (config.useServerRewards) {
                object answer = ServerRewards?.Call<int>("CheckPoints", player.userID);
                if (answer != null) return (int)answer;
            }
            else if (config.useEconomics) {
                object answer = Economics?.Call<int>("Balance", player.userID);
                if (answer != null) return (int)answer;
            }
            return 0;
        }
        private bool takePoints(BasePlayer player, int amount) {
            if (config.useServerRewards) {
                object answer = ServerRewards?.Call<int>("TakePoints", player.userID, amount);
                if (answer == null) return false;
                else return true;
            }
            else if (config.useEconomics) {
                object answer = Economics?.Call<int>("Withdraw", player.userID, (double)amount);
                if (answer == null) return false;
            }
            return false;
        }
#endregion helpers
#region data management
        private class CustomerData {
            public Dictionary<ulong, List<Tracker>> purchaseTrackers = new Dictionary<ulong, List<Tracker>>();
            public CustomerData() {
            }
        }
        void saveData() {
            try {
                CustomerDataFile.WriteObject(customerData);
            }
            catch (Exception E) {
                Puts(E.ToString());
            }
        }
        void loadData() {
            try {
                customerData = CustomerDataFile.ReadObject<CustomerData>();
            }
            catch (Exception E) {
                Puts(E.ToString());
            }
        }
#endregion
#region Config
        private IEnumerator ProcessSellOrders() {
            foreach (Category category in config.Categories) {
                if (!string.IsNullOrEmpty(category.permission)) permission.RegisterPermission(category.permission, this);
                if (!string.IsNullOrEmpty(category.categoryicon)) {
                    ItemDefinition itemDefinition = ItemManager.FindItemDefinition(category.categoryicon);
                    if (itemDefinition == null) guiCreator.registerImage(this, category.safeName, category.categoryicon, imgSizeX : 35, imgSizeY : 35);
                }
                foreach (Product product in category.products) {
                    if (!string.IsNullOrEmpty(product.permission)) permission.RegisterPermission(product.permission, this);
                    if (!string.IsNullOrEmpty(product.imageUrl)) guiCreator.registerImage(this, product.safeName, product.imageUrl, imgSizeX : 384, imgSizeY : 384);
                    if (string.IsNullOrEmpty(product.description) && !string.IsNullOrEmpty(product.shortname)) {
                        ItemDefinition itemDefinition = ItemManager.FindItemDefinition(product.shortname);
                        if (itemDefinition != null) product.description = itemDefinition.displayDescription.english;
                    }
                    yield return null;
                }
#if DEBUG
                Puts($"initialized Category: {category.name}");
#endif
            }
#if DEBUG
            Puts("initialized products");
#endif
        }
        private static ConfigData config;
        private class ConfigData {
            [JsonProperty(PropertyName = "Chat Command")]
            public string command;
            [JsonProperty(PropertyName = "use Server Rewards")]
            public bool useServerRewards;
            [JsonProperty(PropertyName = "use Economics")]
            public bool useEconomics;
            [JsonProperty(PropertyName = "Hide products from customers without permission")]
            public bool hideNonPermission;
            [JsonProperty(PropertyName = "Product Panel Background URL (recommended size: 1400px x 940px)")]
            public string background;
            [JsonProperty(PropertyName = "Default Infopanel Background URL (recommended size: 400px x 400px)")]
            public string defaultInfoBG;
            [JsonProperty(PropertyName = "No Permission Overlay (recommended size: 400px x 400px)")]
            public string noPermissionOverlay;
            [JsonProperty(PropertyName = "cooldown Overlay (recommended size: 400px x 400px)")]
            public string cooldownOverlay;
            [JsonProperty(PropertyName = "Economics/ServerR
// ... [Code preview truncated due to length. Full source in attached file] ...

Автор
15FPS
Скачиваний
0
Просмотры
1
Первый выпуск
Обновление
Оценка
0.00 звёзд 0 оценок
Сверху