battlevox

GUIShop.cs

Dec 14th, 2016
160
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 46.55 KB | None | 0 0
  1. using System.Collections.Generic;
  2. using System;
  3. using System.Linq;
  4.  
  5. using Oxide.Core;
  6. using Oxide.Core.Plugins;
  7. using Oxide.Game.Rust.Cui;
  8.  
  9. using UnityEngine;
  10.  
  11. namespace Oxide.Plugins
  12. {
  13.     [Info("GUIShop", "Reneb", "1.4.1", ResourceId = 1319)]
  14.     class GUIShop : RustPlugin
  15.     {
  16.         private const string ShopOverlayName = "ShopOverlay";
  17.         private const string ShopContentName = "ShopContent";
  18.         private const string ShopDescOverlay = "ShopDescOverlay";
  19.         private readonly int[] steps = { 1, 10, 100, 1000 };
  20.         int playersMask;
  21.  
  22.         //////////////////////////////////////////////////////////////////////////////////////
  23.         // References ////////////////////////////////////////////////////////////////////////
  24.         //////////////////////////////////////////////////////////////////////////////////////
  25.  
  26.         [PluginReference]
  27.         Plugin Economics;
  28.  
  29.         [PluginReference]
  30.         Plugin Kits;
  31.  
  32.         [PluginReference]
  33.         Plugin ImageCache;
  34.  
  35.         void OnServerInitialized()
  36.         {
  37.             displaynameToShortname.Clear();
  38.             foreach (var itemdef in ItemManager.itemList)
  39.             {
  40.                 displaynameToShortname.Add(itemdef.displayName.english.ToLower(), itemdef.shortname);
  41.                 if (string.IsNullOrEmpty(IconUrl)) continue;
  42.                 ImageCache?.CallHook("Add", string.Format(IconUrl, itemdef.shortname));
  43.             }
  44.  
  45.             var shopCategories = DefaultShopCategories();
  46.             CheckCfg("Shop - Shop Categories", ref shopCategories);
  47.             foreach (var shopCategory in shopCategories)
  48.             {
  49.                 var itemdata = shopCategory.Value as Dictionary<string, object>;
  50.                 if (itemdata == null) continue;
  51.                 try
  52.                 {
  53.                     var data = new ItemData();
  54.                     object obj;
  55.                     if (itemdata.TryGetValue("item", out obj))
  56.                     {
  57.                         var itemname = ((string)obj).ToLower();
  58.                         if (displaynameToShortname.ContainsKey(itemname))
  59.                             itemname = displaynameToShortname[itemname];
  60.                         var definition = ItemManager.FindItemDefinition(itemname);
  61.                         if (definition == null)
  62.                         {
  63.                             Puts("ShopCategory: {0} Unknown item: {1}", shopCategory.Key, itemname);
  64.                             continue;
  65.                         }
  66.                         data.Shortname = definition.shortname;
  67.                     }
  68.                     if (itemdata.TryGetValue("cmd", out obj))
  69.                         data.Cmd = ((List<object>)obj).ConvertAll(c => (string)c);
  70.                     double value;
  71.                     if (itemdata.TryGetValue("cooldown", out obj) && double.TryParse((string)obj, out value))
  72.                         data.Cooldown = value;
  73.                     if (itemdata.TryGetValue("buy", out obj) && double.TryParse((string)obj, out value))
  74.                         data.Buy = value;
  75.                     if (itemdata.TryGetValue("sell", out obj) && double.TryParse((string)obj, out value))
  76.                         data.Sell = value;
  77.                     if (itemdata.TryGetValue("fixed", out obj))
  78.                         data.Fixed = Convert.ToBoolean(obj);
  79.                     if (itemdata.TryGetValue("img", out obj))
  80.                         data.Img = (string)obj;
  81.                     ShopCategories[shopCategory.Key] = data;
  82.                 }
  83.                 catch (Exception e)
  84.                 {
  85.                     Puts("Failed to load ShopCategory: {0} Error: {1}", shopCategory.Key, e.Message);
  86.                 }
  87.             }
  88.             if (configChanged) SaveConfig();
  89.  
  90.             foreach (var itemData in ShopCategories.Values)
  91.             {
  92.                 if (string.IsNullOrEmpty(itemData.Img)) continue;
  93.                 ImageCache?.CallHook("Add", itemData.Img);
  94.             }
  95.             if (!Economics) PrintWarning("Economics plugin not found. " + Name + " will not function!");
  96.         }
  97.  
  98.         //////////////////////////////////////////////////////////////////////////////////////
  99.         // Configs Manager ///////////////////////////////////////////////////////////////////
  100.         //////////////////////////////////////////////////////////////////////////////////////
  101.  
  102.         void LoadDefaultConfig() { }
  103.  
  104.         private void CheckCfg<T>(string Key, ref T var)
  105.         {
  106.             if (Config[Key] is T)
  107.                 var = (T) Config[Key];
  108.             else
  109.             {
  110.                 Config[Key] = var;
  111.                 configChanged = true;
  112.             }
  113.         }
  114.  
  115.         class ItemData
  116.         {
  117.             public string Shortname { get; set; }
  118.             public double Cooldown { get; set; }
  119.             public double Buy { get; set; } = -1;
  120.             public double Sell { get; set; } = -1;
  121.             public bool Fixed { get; set; }
  122.             public List<string> Cmd { get; set; }
  123.             public string Img { get; set; }
  124.         }
  125.  
  126.         private Dictionary<string, ItemData> ShopCategories = new Dictionary<string, ItemData>();
  127.         private Dictionary<string, object> Shops = DefaultShops();
  128.         private bool Balance;
  129.         private string IconUrl = string.Empty;
  130.  
  131.         string MessageShowNoEconomics = "Couldn't get informations out of Economics. Is it installed?";
  132.         string MessageBought = "You've successfully bought {0}x {1}";
  133.         string MessageSold = "You've successfully sold {0}x {1}";
  134.         string MessageErrorCooldown = "This item has a cooldown of {0} seconds.";
  135.         string MessageErrorCooldownAmount = "This item has a cooldown and amount is limited to 1.";
  136.         string MessageErrorInventoryFull = "Your inventory is full.";
  137.         string MessageErrorInventorySlots = "Your inventory needs {0} free slots.";
  138.         string MessageErrorNoShop = "This shop doesn't seem to exist.";
  139.         string MessageErrorNoActionShop = "You are not allowed to {0} in this shop";
  140.         string MessageErrorNoNPC = "The NPC owning this shop was not found around you";
  141.         string MessageErrorNoActionItem = "You are not allowed to {0} this item here";
  142.         string MessageErrorItemItem = "WARNING: The admin didn't set this item properly! (item)";
  143.         string MessageErrorItemNoValid = "WARNING: It seems like it's not a valid item";
  144.         string MessageErrorRedeemKit = "WARNING: There was an error while giving you this kit";
  145.         string MessageErrorBuyCmd = "Can't buy multiple";
  146.         string MessageErrorBuyPrice = "WARNING: No buy price was given by the admin, you can't buy this item";
  147.         string MessageErrorSellPrice = "WARNING: No sell price was given by the admin, you can't sell this item";
  148.         string MessageErrorNotEnoughMoney = "You need {0} coins to buy {1} of {2}";
  149.         string MessageErrorNotEnoughSell = "You don't have enough of this item.";
  150.         string MessageErrorNotNothing = "You cannot buy nothing of this item.";
  151.         string MessageErrorItemNoExist = "WARNING: The item you are trying to buy doesn't seem to exist";
  152.         string MessageErrorNPCRange = "You may not use the chat shop. You might need to find the NPC Shops.";
  153.         string MessageErrorBuildingBlocked = "You cannot shop while in building blocked area.";
  154.  
  155.         void Init()
  156.         {
  157.             CheckCfg("Shop - Shop Icon Url", ref IconUrl);
  158.             CheckCfg("Shop - Shop List", ref Shops);
  159.             CheckCfg("Shop - Balance", ref Balance);
  160.             CheckCfg("Message - Error - No Econonomics", ref MessageShowNoEconomics);
  161.             CheckCfg("Message - Bought", ref MessageBought);
  162.             CheckCfg("Message - Sold", ref MessageSold);
  163.             CheckCfg("Message - Error - Cooldown", ref MessageErrorCooldown);
  164.             CheckCfg("Message - Error - Cooldown Amount", ref MessageErrorCooldownAmount);
  165.             CheckCfg("Message - Error - Invetory Full", ref MessageErrorInventoryFull);
  166.             CheckCfg("Message - Error - Invetory Slots", ref MessageErrorInventorySlots);
  167.             CheckCfg("Message - Error - No Shop", ref MessageErrorNoShop);
  168.             CheckCfg("Message - Error - No Action In Shop", ref MessageErrorNoActionShop);
  169.             CheckCfg("Message - Error - No NPC", ref MessageErrorNoNPC);
  170.             CheckCfg("Message - Error - No Action Item", ref MessageErrorNoActionItem);
  171.             CheckCfg("Message - Error - Item Not Set Properly", ref MessageErrorItemItem);
  172.             CheckCfg("Message - Error - Item Not Valid", ref MessageErrorItemNoValid);
  173.             CheckCfg("Message - Error - Redeem Kit", ref MessageErrorRedeemKit);
  174.             CheckCfg("Message - Error - Command Multiple", ref MessageErrorBuyCmd);
  175.             CheckCfg("Message - Error - No Buy Price", ref MessageErrorBuyPrice);
  176.             CheckCfg("Message - Error - No Sell Price", ref MessageErrorSellPrice);
  177.             CheckCfg("Message - Error - Not Enough Money", ref MessageErrorNotEnoughMoney);
  178.             CheckCfg("Message - Error - Not Enough Items", ref MessageErrorNotEnoughSell);
  179.             CheckCfg("Message - Error - Not Nothing", ref MessageErrorNotNothing);
  180.             CheckCfg("Message - Error - Item Doesnt Exist", ref MessageErrorItemNoExist);
  181.             CheckCfg("Message - Error - No Chat Shop", ref MessageErrorNPCRange);
  182.             CheckCfg("Message - Error - Building Blocked", ref MessageErrorBuildingBlocked);
  183.             if (configChanged) SaveConfig();
  184.             LoadData();
  185.         }
  186.  
  187.         void LoadData()
  188.         {
  189.             cooldowns = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<ulong, Dictionary<string, double>>>(nameof(GUIShop));
  190.             buyed = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<string, ulong>>(nameof(GUIShop) + "Buyed");
  191.             selled = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<string, ulong>>(nameof(GUIShop) + "Selled");
  192.         }
  193.  
  194.         void SaveData()
  195.         {
  196.             if (cooldowns != null)
  197.                 Interface.Oxide.DataFileSystem.WriteObject(nameof(GUIShop), cooldowns);
  198.             if (buyed != null)
  199.                 Interface.Oxide.DataFileSystem.WriteObject(nameof(GUIShop) + "Buyed", buyed);
  200.             if (selled != null)
  201.                 Interface.Oxide.DataFileSystem.WriteObject(nameof(GUIShop) + "Selled", selled);
  202.         }
  203.  
  204.         void Unload()
  205.         {
  206.             SaveData();
  207.         }
  208.         void OnServerSave()
  209.         {
  210.             SaveData();
  211.         }
  212.         void OnServerShutdown()
  213.         {
  214.             SaveData();
  215.         }
  216.  
  217.         static int CurrentTime() { return Facepunch.Math.Epoch.Current; }
  218.  
  219.         //////////////////////////////////////////////////////////////////////////////////////
  220.         // Default Shops for Tutorial purpoise ///////////////////////////////////////////////
  221.         //////////////////////////////////////////////////////////////////////////////////////
  222.         static Dictionary<string, object> DefaultShops()
  223.         {
  224.             var shops = new Dictionary<string, object>
  225.             {
  226.                 {
  227.                     "chat", new Dictionary<string, object>
  228.                     {
  229.                         {"buy", new List<object> {"Build Kit"}},
  230.                         {"description", "You currently have {0} coins to spend in this builders shop"},
  231.                         {"name", "Build"}
  232.                     }
  233.                 },
  234.                 {
  235.                     "5498734", new Dictionary<string, object>
  236.                     {
  237.                         {"description", "You currently have {0} coins to spend in this weapons shop"},
  238.                         {"name", "Weaponsmith Shop"},
  239.                         {"buy", new List<object> {"Assault Rifle", "Bolt Action Rifle"}},
  240.                         {"sell", new List<object> {"Assault Rifle", "Bolt Action Rifle"}}
  241.                     }
  242.                 },
  243.                 {
  244.                     "1234567", new Dictionary<string, object>
  245.                     {
  246.                         {"description", "You currently have {0} coins to spend in this farmers market"},
  247.                         {"name", "Fruit Market"},
  248.                         {"buy", new List<object> {"Apple", "BlueBerries", "Assault Rifle", "Bolt Action Rifle"}},
  249.                         {"sell", new List<object> {"Apple", "BlueBerries", "Assault Rifle", "Bolt Action Rifle"}}
  250.                     }
  251.                 }
  252.             };
  253.             return shops;
  254.         }
  255.         static Dictionary<string, object> DefaultShopCategories()
  256.         {
  257.             var dsc = new Dictionary<string, object>
  258.             {
  259.                 {
  260.                     "Assault Rifle", new Dictionary<string, object>
  261.                     {
  262.                         {"item", "assault rifle"},
  263.                         {"buy", "10"},
  264.                         {"sell", "8"}
  265.                     }
  266.                 },
  267.                 {
  268.                     "Bolt Action Rifle", new Dictionary<string, object>
  269.                     {
  270.                         {"item", "bolt action rifle"},
  271.                         {"buy", "10"}, {"sell", "8"}
  272.                     }
  273.                 },
  274.                 {
  275.                     "Build Kit", new Dictionary<string, object>
  276.                     {
  277.                         {"item", "kitbuild"},
  278.                         {"buy", "10"},
  279.                         {"sell", "8"},
  280.                         {"img", "http://oxidemod.org/data/resource_icons/0/715.jpg?1425682952"}
  281.                     }
  282.                 },
  283.                 {
  284.                     "Apple", new Dictionary<string, object>
  285.                     {
  286.                         {"item", "apple"},
  287.                         {"buy", "1"},
  288.                         {"sell", "1"}
  289.                     }
  290.                 },
  291.                 {
  292.                     "BlueBerries", new Dictionary<string, object>
  293.                     {
  294.                         {"item", "blueberries"},
  295.                         {"buy", "1"},
  296.                         {"sell", "1"}
  297.                     }
  298.                 }
  299.             };
  300.             return dsc;
  301.         }
  302.  
  303.  
  304.  
  305.         //////////////////////////////////////////////////////////////////////////////////////
  306.         // Item Management ///////////////////////////////////////////////////////////////////
  307.         //////////////////////////////////////////////////////////////////////////////////////
  308.         readonly Dictionary<string, string> displaynameToShortname = new Dictionary<string, string>();
  309.  
  310.         //////////////////////////////////////////////////////////////////////////////////////
  311.         // Oxide Hooks ///////////////////////////////////////////////////////////////////////
  312.         //////////////////////////////////////////////////////////////////////////////////////
  313.  
  314.         void Loaded()
  315.         {
  316.             playersMask = LayerMask.GetMask("Player (Server)");
  317.         }
  318.  
  319.         void OnUseNPC(BasePlayer npc, BasePlayer player)
  320.         {
  321.             if (!Shops.ContainsKey(npc.UserIDString)) return;
  322.             ShowShop(player, npc.UserIDString, 0);
  323.         }
  324.  
  325.         //////////////////////////////////////////////////////////////////////////////////////
  326.         // GUI ///////////////////////////////////////////////////////////////////////////////
  327.         //////////////////////////////////////////////////////////////////////////////////////
  328.  
  329.         private static CuiElementContainer CreateShopOverlay(string shopname)
  330.         {
  331.             return new CuiElementContainer
  332.             {
  333.                 {
  334.                     new CuiPanel
  335.                     {
  336.                         Image = {Color = "0.1 0.1 0.1 0.8"},
  337.                         RectTransform = {AnchorMin = "0 0", AnchorMax = "1 1"},
  338.                         CursorEnabled = true
  339.                     },
  340.                     new CuiElement().Parent,
  341.                     ShopOverlayName
  342.                 },
  343.                 {
  344.                     new CuiLabel
  345.                     {
  346.                         Text = {Text = shopname, FontSize = 30, Align = TextAnchor.MiddleCenter},
  347.                         RectTransform = {AnchorMin = "0.3 0.8", AnchorMax = "0.7 0.9"}
  348.                     },
  349.                     ShopOverlayName
  350.                 },
  351.                 {
  352.                     new CuiLabel
  353.                     {
  354.                         Text = {Text = "Item", FontSize = 20, Align = TextAnchor.MiddleLeft},
  355.                         RectTransform = {AnchorMin = "0.2 0.6", AnchorMax = "0.4 0.65"}
  356.                     },
  357.                     ShopOverlayName
  358.                 },
  359.                 {
  360.                     new CuiLabel
  361.                     {
  362.                         Text = {Text = "Buy", FontSize = 20, Align = TextAnchor.MiddleLeft},
  363.                         RectTransform = {AnchorMin = "0.55 0.6", AnchorMax = "0.7 0.65"}
  364.                     },
  365.                     ShopOverlayName
  366.                 },
  367.                 {
  368.                     new CuiLabel
  369.                     {
  370.                         Text = {Text = "Sell", FontSize = 20, Align = TextAnchor.MiddleLeft},
  371.                         RectTransform = {AnchorMin = "0.75 0.6", AnchorMax = "0.9 0.65"}
  372.                     },
  373.                     ShopOverlayName
  374.                 },
  375.                 {
  376.                     new CuiButton
  377.                     {
  378.                         Button = {Close = ShopOverlayName, Color = "0.5 0.5 0.5 0.2"},
  379.                         RectTransform = {AnchorMin = "0.5 0.15", AnchorMax = "0.7 0.2"},
  380.                         Text = {Text = "Close", FontSize = 20, Align = TextAnchor.MiddleCenter}
  381.                     },
  382.                     ShopOverlayName
  383.                 }
  384.             };
  385.         }
  386.  
  387.         private readonly CuiLabel shopDescription = new CuiLabel
  388.         {
  389.             Text = { Text = "{shopdescription}", FontSize = 15, Align = TextAnchor.MiddleCenter },
  390.             RectTransform = { AnchorMin = "0.2 0.7", AnchorMax = "0.8 0.79" }
  391.         };
  392.  
  393.         private CuiElementContainer CreateShopItemEntry(string price, float ymax, float ymin, string shop, string item, string color, bool sell, bool cooldown)
  394.         {
  395.             var container = new CuiElementContainer
  396.             {
  397.                 {
  398.                     new CuiLabel
  399.                     {
  400.                         Text = {Text = price, FontSize = 15, Align = TextAnchor.MiddleLeft},
  401.                         RectTransform = {AnchorMin = $"{(sell ? 0.725 : 0.45)} {ymin}", AnchorMax = $"{(sell ? 0.755 : 0.5)} {ymax}"}
  402.                     },
  403.                     ShopContentName
  404.                 }
  405.             };
  406.             for (var i = 0; i < steps.Length; i++)
  407.             {
  408.                 container.Add(new CuiButton
  409.                 {
  410.                     Button = {Command = $"shop.{(sell ? "sell" : "buy")} {shop} {item} {steps[i]}", Color = color},
  411.                     RectTransform = {AnchorMin = $"{(sell ? 0.775 : 0.5) + i*0.03 + 0.001} {ymin}", AnchorMax = $"{(sell ? 0.805 : 0.53) + i*0.03 - 0.001} {ymax}"},
  412.                     Text = {Text = steps[i].ToString(), FontSize = 15, Align = TextAnchor.MiddleCenter}
  413.                 }, ShopContentName);
  414.                 //if (cooldown) break;
  415.             }
  416.             if (!cooldown)
  417.             {
  418.                 container.Add(new CuiButton
  419.                 {
  420.                     Button = { Command = $"shop.{(sell ? "sell" : "buy")} {shop} {item} all", Color = color },
  421.                     RectTransform = { AnchorMin = $"{(sell ? 0.775 : 0.5) + steps.Length * 0.03 + 0.001} {ymin}", AnchorMax = $"{(sell ? 0.805 : 0.53) + steps.Length * 0.03 - 0.001} {ymax}" },
  422.                     Text = { Text = "All", FontSize = 15, Align = TextAnchor.MiddleCenter }
  423.                 }, ShopContentName);
  424.             }
  425.             return container;
  426.         }
  427.  
  428.         private CuiElementContainer CreateShopItemIcon(string name, float ymax, float ymin, ItemData data)
  429.         {
  430.             string url = null;
  431.             if (!string.IsNullOrEmpty(data.Img))
  432.                 url = data.Img;
  433.             else if (!string.IsNullOrEmpty(data.Shortname))
  434.                 url = string.Format(IconUrl, data.Shortname);
  435.             var label = new CuiLabel
  436.             {
  437.                 Text = { Text = name, FontSize = 15, Align = TextAnchor.MiddleLeft },
  438.                 RectTransform = { AnchorMin = $"0.1 {ymin}", AnchorMax = $"0.3 {ymax}" }
  439.             };
  440.             if (string.IsNullOrEmpty(url))
  441.                 return new CuiElementContainer
  442.                 {
  443.                     {
  444.                         label,
  445.                         ShopContentName
  446.                     }
  447.                 };
  448.             var rawImage = new CuiRawImageComponent();
  449.             if (url.StartsWith("http") || url.StartsWith("file"))
  450.             {
  451.                 var id = (string)ImageCache?.CallHook("Get", url);
  452.                 if (!string.IsNullOrEmpty(id))
  453.                     rawImage.Png = id;
  454.                 else
  455.                     rawImage.Url = url;
  456.                 rawImage.Sprite = "assets/content/textures/generic/fulltransparent.tga";
  457.             }
  458.             else
  459.                 rawImage.Sprite = url;
  460.             var container = new CuiElementContainer
  461.             {
  462.                 {
  463.                     label,
  464.                     ShopContentName
  465.                 },
  466.                 new CuiElement
  467.                 {
  468.                     Parent = ShopContentName,
  469.                     Components =
  470.                     {
  471.                         rawImage,
  472.                         new CuiRectTransformComponent {AnchorMin = $"0.05 {ymin}", AnchorMax = $"0.08 {ymax}"}
  473.                     }
  474.                 }
  475.             };
  476.             return container;
  477.         }
  478.  
  479.         private static CuiElementContainer CreateShopChangePage(string currentshop, int shoppageminus, int shoppageplus)
  480.         {
  481.             return new CuiElementContainer
  482.             {
  483.                 {
  484.                     new CuiButton
  485.                     {
  486.                         Button = {Command = $"shop.show {currentshop} {shoppageminus}", Color = "0.5 0.5 0.5 0.2"},
  487.                         RectTransform = {AnchorMin = "0.2 0.15", AnchorMax = "0.3 0.2"},
  488.                         Text = {Text = "<<", FontSize = 20, Align = TextAnchor.MiddleCenter}
  489.                     },
  490.                     ShopOverlayName,
  491.                     "ButtonBack"
  492.                 },
  493.                 {
  494.                     new CuiButton
  495.                     {
  496.                         Button = {Command = $"shop.show {currentshop} {shoppageplus}", Color = "0.5 0.5 0.5 0.2"},
  497.                         RectTransform = {AnchorMin = "0.35 0.15", AnchorMax = "0.45 0.2"},
  498.                         Text = {Text = ">>", FontSize = 20, Align = TextAnchor.MiddleCenter}
  499.                     },
  500.                     ShopOverlayName,
  501.                     "ButtonForward"
  502.                 }
  503.             };
  504.         }
  505.  
  506.         readonly Hash<ulong, int> shopPage = new Hash<ulong, int>();
  507.         private Dictionary<ulong, Dictionary<string, double>> cooldowns;
  508.         private Dictionary<string, ulong> buyed;
  509.         private Dictionary<string, ulong> selled;
  510.         private bool configChanged;
  511.  
  512.         void ShowShop(BasePlayer player, string shopid, int from = 0, bool fullPaint = true, bool refreshMoney = false)
  513.         {
  514.             shopPage[player.userID] = from;
  515.             object shopObj;
  516.             if (!Shops.TryGetValue(shopid, out shopObj))
  517.             {
  518.                 SendReply(player, MessageErrorNoShop);
  519.                 return;
  520.             }
  521.             if (Economics == null)
  522.             {
  523.                 SendReply(player, MessageShowNoEconomics);
  524.                 return;
  525.             }
  526.             var playerCoins = (double) Economics.CallHook("GetPlayerMoney", player.userID);
  527.  
  528.             var shop = (Dictionary<string, object>) shopObj;
  529.  
  530.             shopDescription.Text.Text = string.Format((string) shop["description"], playerCoins);
  531.  
  532.             if (refreshMoney)
  533.             {
  534.                 CuiHelper.DestroyUi(player, ShopDescOverlay);
  535.                 CuiHelper.AddUi(player, new CuiElementContainer { { shopDescription, ShopOverlayName, ShopDescOverlay } });
  536.                 return;
  537.             }
  538.             DestroyUi(player, fullPaint);
  539.             CuiElementContainer container;
  540.             if (fullPaint)
  541.             {
  542.                 container = CreateShopOverlay((string) shop["name"]);
  543.                 container.Add(shopDescription, ShopOverlayName, ShopDescOverlay);
  544.             }
  545.             else
  546.                 container = new CuiElementContainer();
  547.             container.Add(new CuiPanel
  548.             {
  549.                 Image = { Color = "0 0 0 0" },
  550.                 RectTransform = { AnchorMin = "0 0.2", AnchorMax = "1 0.6" }
  551.             }, ShopOverlayName, ShopContentName);
  552.             if (from < 0)
  553.             {
  554.                 CuiHelper.AddUi(player, container);
  555.                 return;
  556.             }
  557.  
  558.             var itemslist = new Dictionary<string, Dictionary<string, bool>>();
  559.             object type;
  560.             if (shop.TryGetValue("sell", out type))
  561.             {
  562.                 foreach (string itemname in (List<object>)type)
  563.                 {
  564.                     Dictionary<string, bool> itemEntry;
  565.                     if (!itemslist.TryGetValue(itemname, out itemEntry))
  566.                         itemslist[itemname] = itemEntry = new Dictionary<string, bool>();
  567.                     itemEntry["sell"] = true;
  568.                 }
  569.             }
  570.             if (shop.TryGetValue("buy", out type))
  571.             {
  572.                 foreach (string itemname in (List<object>)type)
  573.                 {
  574.                     Dictionary<string, bool> itemEntry;
  575.                     if (!itemslist.TryGetValue(itemname, out itemEntry))
  576.                         itemslist[itemname] = itemEntry = new Dictionary<string, bool>();
  577.                     itemEntry["buy"] = true;
  578.                 }
  579.             }
  580.             var current = 0;
  581.             foreach (var pair in itemslist)
  582.             {
  583.                 ItemData data;
  584.                 if (!ShopCategories.TryGetValue(pair.Key, out data)) continue;
  585.  
  586.                 if (current >= from && current < from + 7)
  587.                 {
  588.                     var pos = 0.85f - 0.125f * (current - from);
  589.  
  590.                     var cooldown = data.Cooldown > 0;
  591.                     var name = pair.Key;
  592.                     if (cooldown)
  593.                         name += $" ({FormatTime((long)data.Cooldown)})";
  594.                     container.AddRange(CreateShopItemIcon(name, pos + 0.125f, pos, data));
  595.                     var buyed = false;
  596.                     if (cooldown)
  597.                     {
  598.                         Dictionary<string, double> itemCooldowns;
  599.                         double itemCooldown;
  600.                         if (cooldowns.TryGetValue(player.userID, out itemCooldowns)
  601.                             && itemCooldowns.TryGetValue(pair.Key, out itemCooldown)
  602.                             && itemCooldown > CurrentTime())
  603.                         {
  604.                             buyed = true;
  605.                             container.Add(new CuiLabel
  606.                             {
  607.                                 Text = {Text = GetBuyPrice(data).ToString(), FontSize = 15, Align = TextAnchor.MiddleLeft},
  608.                                 RectTransform = {AnchorMin = $"0.45 {pos}", AnchorMax = $"0.5 {pos + 0.125f}"}
  609.                             }, ShopContentName);
  610.                             container.Add(new CuiLabel
  611.                             {
  612.                                 Text = {Text = FormatTime((long)(itemCooldown - CurrentTime())), FontSize = 15, Align = TextAnchor.MiddleLeft},
  613.                                 RectTransform = {AnchorMin = $"0.5 {pos}", AnchorMax = $"0.6 {pos + 0.125f}"}
  614.                             }, ShopContentName);
  615.                             //current++;
  616.                             //continue;
  617.                         }
  618.                     }
  619.                     if (!buyed && pair.Value.ContainsKey("buy"))
  620.                         container.AddRange(CreateShopItemEntry(GetBuyPrice(data).ToString(), pos + 0.125f, pos, $"'{shopid}'", $"'{pair.Key}'", "0 0.6 0 0.1", false, cooldown));
  621.                     if (pair.Value.ContainsKey("sell"))
  622.                         container.AddRange(CreateShopItemEntry(GetSellPrice(data).ToString(), pos + 0.125f, pos, $"'{shopid}'", $"'{pair.Key}'", "1 0 0 0.1", true, cooldown));
  623.                 }
  624.                 current++;
  625.             }
  626.             var minfrom = from <= 7 ? 0 : from - 7;
  627.             var maxfrom = from + 7 >= current ? from : from + 7;
  628.             container.AddRange(CreateShopChangePage(shopid, minfrom, maxfrom));
  629.             CuiHelper.AddUi(player, container);
  630.         }
  631.  
  632.         double GetBuyPrice(ItemData data)
  633.         {
  634.             if (!Balance || data.Fixed) return data.Buy;
  635.             return Math.Round(data.Buy * GetFactor(data), 2);
  636.         }
  637.  
  638.         double GetSellPrice(ItemData data)
  639.         {
  640.             if (!Balance || data.Fixed) return data.Sell;
  641.             return Math.Round(data.Sell * GetFactor(data), 2);
  642.         }
  643.  
  644.         double GetFactor(ItemData data)
  645.         {
  646.             if (data.Shortname == null) return 1;
  647.             var itemname = data.Shortname;
  648.             ulong buy;
  649.             if (!buyed.TryGetValue(itemname, out buy))
  650.                 buy = 1;
  651.             ulong sell;
  652.             if (!selled.TryGetValue(itemname, out sell))
  653.                 sell = 1;
  654.             return Math.Min(Math.Max(buy / (double)sell, .25), 4);
  655.         }
  656.  
  657.         private static string FormatTime(long seconds)
  658.         {
  659.             var timespan = TimeSpan.FromSeconds(seconds);
  660.             return string.Format(timespan.TotalHours >= 1 ? "{2:00}:{0:00}:{1:00}" : "{0:00}:{1:00}", timespan.Minutes, timespan.Seconds, Math.Floor(timespan.TotalHours));
  661.         }
  662.         //////////////////////////////////////////////////////////////////////////////////////
  663.         // Shop Functions ////////////////////////////////////////////////////////////////////
  664.         //////////////////////////////////////////////////////////////////////////////////////
  665.  
  666.         object CanDoAction(BasePlayer player, string shop, string item, string ttype)
  667.         {
  668.             var shopdata = (Dictionary<string, object>) Shops[shop];
  669.             if (!shopdata.ContainsKey(ttype))
  670.                 return string.Format(MessageErrorNoActionShop, ttype);
  671.             var actiondata = (List<object>) shopdata[ttype];
  672.             if (!actiondata.Contains(item))
  673.                 return string.Format(MessageErrorNoActionItem, ttype);
  674.             return true;
  675.         }
  676.  
  677.         bool CanFindNPC(Vector3 pos, string npcid)
  678.         {
  679.             return Physics.OverlapSphere(pos, 3f, playersMask).Select(col => col.GetComponentInParent<BasePlayer>()).Any(player => player != null && player.UserIDString == npcid);
  680.         }
  681.  
  682.         object CanShop(BasePlayer player, string shopname)
  683.         {
  684.             if (!Shops.ContainsKey(shopname)) return MessageErrorNoShop;
  685.             if (shopname != "chat" && !CanFindNPC(player.transform.position, shopname))
  686.                 return MessageErrorNoNPC;
  687.             return true;
  688.         }
  689.  
  690.         //////////////////////////////////////////////////////////////////////////////////////
  691.         // Buy Functions /////////////////////////////////////////////////////////////////////
  692.         //////////////////////////////////////////////////////////////////////////////////////
  693.  
  694.         object TryShopBuy(BasePlayer player, string shop, string item, int amount)
  695.         {
  696.             if (amount <= 0) return false;
  697.             object success = CanShop(player, shop);
  698.             if (success is string) return success;
  699.             success = CanDoAction(player, shop, item, "buy");
  700.             if (success is string) return success;
  701.             success = CanBuy(player, item, amount);
  702.             if (success is string) return success;
  703.             success = TryGive(player, item, amount);
  704.             if (success is string) return success;
  705.             var data = ShopCategories[item];
  706.             var tryShopBuy = Economics?.CallHook("Withdraw", player.userID, GetBuyPrice(data) * amount);
  707.             if (tryShopBuy == null || tryShopBuy is bool && !(bool) tryShopBuy)
  708.                 return MessageShowNoEconomics;
  709.             if (data.Cooldown > 0)
  710.             {
  711.                 Dictionary<string, double> itemCooldowns;
  712.                 if (!cooldowns.TryGetValue(player.userID, out itemCooldowns))
  713.                     cooldowns[player.userID] = itemCooldowns = new Dictionary<string, double>();
  714.                 itemCooldowns[item] = CurrentTime() + data.Cooldown*amount;
  715.             }
  716.             if (!string.IsNullOrEmpty(data.Shortname))
  717.             {
  718.                 ulong count;
  719.                 buyed.TryGetValue(data.Shortname, out count);
  720.                 buyed[data.Shortname] = count + (ulong) amount;
  721.             }
  722.             return tryShopBuy;
  723.         }
  724.  
  725.         object TryGive(BasePlayer player, string item, int amount)
  726.         {
  727.             var data = ShopCategories[item];
  728.             if (!string.IsNullOrEmpty(data.Shortname))
  729.             {
  730.                 if (player.inventory.containerMain.IsFull()) return MessageErrorInventoryFull;
  731.                 object iskit = Kits?.CallHook("isKit", data.Shortname);
  732.                 if (iskit is bool && (bool)iskit)
  733.                 {
  734.                     object successkit = Kits.CallHook("GiveKit", player, data.Shortname);
  735.                     if (successkit is bool && !(bool)successkit) return MessageErrorRedeemKit;
  736.                     Puts("Player: {0} Buyed Kit: {1}", player.displayName, data.Shortname);
  737.                     return true;
  738.                 }
  739.                 object success = GiveItem(player, data, amount, player.inventory.containerMain);
  740.                 if (success is string) return success;
  741.                 Puts("Player: {0} Buyed Item: {1} x{2}", player.displayName, data.Shortname, amount);
  742.             }
  743.             if (data.Cmd != null)
  744.             {
  745.                 var cmds = data.Cmd;
  746.                 for (var i = 0; i < cmds.Count; i++)
  747.                 {
  748.                     var c = cmds[i]
  749.                         .Replace("$player.id", player.UserIDString)
  750.                         .Replace("$player.name", player.displayName)
  751.                         .Replace("$player.x", player.transform.position.x.ToString())
  752.                         .Replace("$player.y", player.transform.position.y.ToString())
  753.                         .Replace("$player.z", player.transform.position.z.ToString());
  754.                     if (c.StartsWith("shop.show close", StringComparison.OrdinalIgnoreCase))
  755.                         NextTick(() => ConsoleSystem.Run.Server.Normal(c));
  756.                     else
  757.                         ConsoleSystem.Run.Server.Normal(c);
  758.                 }
  759.                 Puts("Player: {0} Buyed command: {1}", player.displayName, item);
  760.             }
  761.             return true;
  762.         }
  763.  
  764.         private int GetAmountBuy(BasePlayer player, string item)
  765.         {
  766.             if (player.inventory.containerMain.IsFull()) return 0;
  767.             var data = ShopCategories[item];
  768.             var definition = ItemManager.FindItemDefinition(data.Shortname);
  769.             if (definition == null) return 0;
  770.             var stack = definition.stackable;
  771.             if (stack < 1) stack = 1;
  772.             var freeSlots = player.inventory.containerMain.capacity - player.inventory.containerMain.itemList.Count;
  773.             var slotAmount = freeSlots*stack;
  774.             var balanceAmount = (int)((double)Economics.CallHook("GetPlayerMoney", player.userID) / GetBuyPrice(data));
  775.             return slotAmount < balanceAmount ? slotAmount : balanceAmount;
  776.         }
  777.  
  778.         private object GiveItem(BasePlayer player, ItemData data, int amount, ItemContainer pref)
  779.         {
  780.             if (amount <= 0) return MessageErrorNotNothing;
  781.             var definition = ItemManager.FindItemDefinition(data.Shortname);
  782.             if (definition == null) return MessageErrorItemNoExist;
  783.             int stack = definition.stackable;
  784.             if (stack < 1) stack = 1;
  785.             if (pref.itemList.Count + Math.Ceiling(amount / (float)stack) > pref.capacity)
  786.                 return string.Format(MessageErrorInventorySlots, Math.Ceiling(amount / (float)stack));
  787.             for (var i = amount; i > 0; i = i - stack)
  788.             {
  789.                 var giveamount = i >= stack ? stack : i;
  790.                 if (giveamount < 1) return true;
  791.                 var item = ItemManager.CreateByItemID(definition.itemid, giveamount);
  792.                 if (!player.inventory.GiveItem(item, pref))
  793.                     item.Remove(0);
  794.             }
  795.             return true;
  796.         }
  797.         object CanBuy(BasePlayer player, string item, int amount)
  798.         {
  799.             if (Economics == null) return MessageShowNoEconomics;
  800.             if (!ShopCategories.ContainsKey(item)) return MessageErrorItemNoValid;
  801.  
  802.             var data = ShopCategories[item];
  803.             if (data.Buy < 0) return MessageErrorBuyPrice;
  804.             if (data.Cmd != null && amount > 1) return MessageErrorBuyCmd;
  805.             var buyprice = GetBuyPrice(data);
  806.  
  807.             var playerCoins = (double) Economics.CallHook("GetPlayerMoney", player.userID);
  808.             if (playerCoins < buyprice*amount)
  809.                 return string.Format(MessageErrorNotEnoughMoney, buyprice*amount, amount, item);
  810.             if (data.Cooldown > 0)
  811.             {
  812.                 //if (data.Cmd != null && amount > 1)
  813.                 //    return MessageErrorCooldownAmount;
  814.                 Dictionary<string, double> itemCooldowns;
  815.                 double itemCooldown;
  816.                 if (cooldowns.TryGetValue(player.userID, out itemCooldowns)
  817.                     && itemCooldowns.TryGetValue(item, out itemCooldown)
  818.                     && itemCooldown > CurrentTime())
  819.                 {
  820.                     return string.Format(MessageErrorCooldown, FormatTime((long) (itemCooldown - CurrentTime())));
  821.                 }
  822.             }
  823.             return true;
  824.         }
  825.  
  826.         //////////////////////////////////////////////////////////////////////////////////////
  827.         // Sell Functions ////////////////////////////////////////////////////////////////////
  828.         //////////////////////////////////////////////////////////////////////////////////////
  829.  
  830.         object TryShopSell(BasePlayer player, string shop, string item, int amount)
  831.         {
  832.             object success = CanShop(player, shop);
  833.             if (success is string) return success;
  834.             success = CanDoAction(player, shop, item, "sell");
  835.             if (success is string) return success;
  836.             success = CanSell(player, item, amount);
  837.             if (success is string) return success;
  838.             success = TrySell(player, item, amount);
  839.             if (success is string) return success;
  840.             var data = ShopCategories[item];
  841.             /*if (itemdata.ContainsKey("cooldown"))
  842.             {
  843.                 var cooldown = Convert.ToDouble(itemdata["cooldown"]);
  844.                 if (cooldown > 0)
  845.                 {
  846.                     Dictionary<string, double> itemCooldowns;
  847.                     if (!cooldowns.TryGetValue(player.userID, out itemCooldowns))
  848.                         cooldowns[player.userID] = itemCooldowns = new Dictionary<string, double>();
  849.                     itemCooldowns[item] = CurrentTime() + cooldown * amount;
  850.                 }
  851.             }*/
  852.             Economics?.CallHook("Deposit", player.userID, GetSellPrice(data) * amount);
  853.             if (!string.IsNullOrEmpty(data.Shortname))
  854.             {
  855.                 ulong count;
  856.                 selled.TryGetValue(data.Shortname, out count);
  857.                 selled[data.Shortname] = count + (ulong)amount;
  858.             }
  859.             return true;
  860.         }
  861.         object TrySell(BasePlayer player, string item, int amount)
  862.         {
  863.             var data = ShopCategories[item];
  864.             if (string.IsNullOrEmpty(data.Shortname)) return MessageErrorItemItem;
  865.             object iskit = Kits?.CallHook("isKit", data.Shortname);
  866.  
  867.             if (iskit is bool && (bool)iskit) return "You can't sell kits";
  868.             object success = TakeItem(player, data, amount);
  869.             if (success is string) return success;
  870.             Puts("Player: {0} Selled Item: {1} x{2}", player.displayName, data.Shortname, amount);
  871.             return true;
  872.         }
  873.  
  874.         private int GetAmountSell(BasePlayer player, string item)
  875.         {
  876.             var data = ShopCategories[item];
  877.             var definition = ItemManager.FindItemDefinition(data.Shortname);
  878.             //Puts("Def: {0}", definition?.shortname);
  879.             if (definition == null) return 0;
  880.             //Puts("GetAmount: {0} {1}", definition.shortname, player.inventory.containerMain.GetAmount(definition.itemid, true));
  881.             return player.inventory.containerMain.GetAmount(definition.itemid, true);
  882.         }
  883.         private object TakeItem(BasePlayer player, ItemData data, int amount)
  884.         {
  885.             if (amount <= 0) return MessageErrorNotEnoughSell;
  886.             var definition = ItemManager.FindItemDefinition(data.Shortname);
  887.             if (definition == null) return MessageErrorItemNoExist;
  888.  
  889.             var pamount = player.inventory.GetAmount(definition.itemid);
  890.             if (pamount < amount) return MessageErrorNotEnoughSell;
  891.             player.inventory.Take(null, definition.itemid, amount);
  892.             return true;
  893.         }
  894.  
  895.         object CanSell(BasePlayer player, string item, int amount)
  896.         {
  897.             if (!ShopCategories.ContainsKey(item)) return MessageErrorItemNoValid;
  898.             var itemdata = ShopCategories[item];
  899.             if (itemdata.Sell < 0) return MessageErrorSellPrice;
  900.             if (false && itemdata.Cooldown > 0)
  901.             {
  902.                 if (amount > 1)
  903.                     return MessageErrorCooldownAmount;
  904.                 Dictionary<string, double> itemCooldowns;
  905.                 double itemCooldown;
  906.                 if (cooldowns.TryGetValue(player.userID, out itemCooldowns)
  907.                     && itemCooldowns.TryGetValue(item, out itemCooldown)
  908.                     && itemCooldown > CurrentTime())
  909.                 {
  910.                     return string.Format(MessageErrorCooldown, FormatTime((long) (itemCooldown - CurrentTime())));
  911.                 }
  912.             }
  913.             return true;
  914.         }
  915.  
  916.         void DestroyUi(BasePlayer player, bool full = false)
  917.         {
  918.             CuiHelper.DestroyUi(player, ShopContentName);
  919.             CuiHelper.DestroyUi(player, "ButtonForward");
  920.             CuiHelper.DestroyUi(player, "ButtonBack");
  921.             if (!full) return;
  922.             CuiHelper.DestroyUi(player, ShopDescOverlay);
  923.             CuiHelper.DestroyUi(player, ShopOverlayName);
  924.         }
  925.         //////////////////////////////////////////////////////////////////////////////////////
  926.         // Chat Commands /////////////////////////////////////////////////////////////////////
  927.         //////////////////////////////////////////////////////////////////////////////////////
  928.         [ChatCommand("shop")]
  929.         void cmdShop(BasePlayer player, string command, string[] args)
  930.         {
  931.             if(!Shops.ContainsKey("chat"))
  932.             {
  933.                 SendReply(player, MessageErrorNPCRange);
  934.                 return;
  935.             }
  936.             if (!player.CanBuild())
  937.             {
  938.                 SendReply(player, MessageErrorBuildingBlocked);
  939.                 return;
  940.             }
  941.             ShowShop(player, "chat");
  942.         }
  943.  
  944.         //////////////////////////////////////////////////////////////////////////////////////
  945.         // Console Commands //////////////////////////////////////////////////////////////////
  946.         //////////////////////////////////////////////////////////////////////////////////////
  947.         [ConsoleCommand("shop.show")]
  948.         void ccmdShopShow(ConsoleSystem.Arg arg)
  949.         {
  950.             if (!arg.HasArgs(2)) return;
  951.             var shopid = arg.GetString(0).Replace("'", "");
  952.             if (shopid.Equals("close", StringComparison.OrdinalIgnoreCase))
  953.             {
  954.                 var targetPlayer = arg.GetPlayerOrSleeper(1);
  955.                 DestroyUi(targetPlayer, true);
  956.                 return;
  957.             }
  958.             var player = arg.Player();
  959.             if (player == null) return;
  960.             var shoppage = arg.GetInt(1);
  961.             ShowShop(player, shopid, shoppage, false);
  962.         }
  963.  
  964.         [ConsoleCommand("shop.buy")]
  965.         void ccmdShopBuy(ConsoleSystem.Arg arg)
  966.         {
  967.             if (!arg.HasArgs(3)) return;
  968.             var player = arg.Player();
  969.             if (player == null) return;
  970.             object success = Interface.Oxide.CallHook("canShop", player);
  971.             if(success != null)
  972.             {
  973.                 SendReply(player, success as string ?? "You are not allowed to shop at the moment");
  974.                 return;
  975.             }
  976.  
  977.             string shop = arg.Args[0].Replace("'", "");
  978.             string item = arg.Args[1].Replace("'", "");
  979.             int amount = arg.Args[2].Equals("all") ? GetAmountBuy(player, item) : Convert.ToInt32(arg.Args[2]);
  980.             success = TryShopBuy(player, shop, item, amount);
  981.             if(success is string)
  982.             {
  983.                 SendReply(player, (string)success);
  984.                 return;
  985.             }
  986.             SendReply(player, string.Format(MessageBought, amount, item));
  987.             ShowShop(player, shop, shopPage[player.userID], false, true);
  988.         }
  989.         [ConsoleCommand("shop.sell")]
  990.         void ccmdShopSell(ConsoleSystem.Arg arg)
  991.         {
  992.             if (!arg.HasArgs(3)) return;
  993.             var player = arg.Player();
  994.             if (player == null) return;
  995.             object success = Interface.Oxide.CallHook("canShop", player);
  996.             if (success != null)
  997.             {
  998.                 string message = "You are not allowed to shop at the moment";
  999.                 if (success is string)
  1000.                     message = (string)success;
  1001.                 SendReply(player, message);
  1002.                 return;
  1003.             }
  1004.             string shop = arg.Args[0].Replace("'", "");
  1005.             string item = arg.Args[1].Replace("'", "");
  1006.             int amount = arg.Args[2].Equals("all") ? GetAmountSell(player, item) : Convert.ToInt32(arg.Args[2]);
  1007.             success = TryShopSell(player, shop, item, amount);
  1008.             if (success is string)
  1009.             {
  1010.                 SendReply(player, (string)success);
  1011.                 return;
  1012.             }
  1013.             SendReply(player, string.Format(MessageSold, amount, item));
  1014.             ShowShop(player, shop, shopPage[player.userID], false, true);
  1015.         }
  1016.     }
  1017. }
Add Comment
Please, Sign In to add comment