/*▄▄▄ ███▄ ▄███▓ ▄████ ▄▄▄██▀▀▀▓█████▄▄▄█████▓ ▓█████▄ ▓██▒▀█▀ ██▒ ██▒ ▀█▒ ▒██ ▓█ ▀▓ ██▒ ▓▒ ▒██▒ ▄██▓██ ▓██░▒██░▄▄▄░ ░██ ▒███ ▒ ▓██░ ▒░ ▒██░█▀ ▒██ ▒██ ░▓█ ██▓▓██▄██▓ ▒▓█ ▄░ ▓██▓ ░ ░▓█ ▀█▓▒██▒ ░██▒░▒▓███▀▒ ▓███▒ ░▒████▒ ▒██▒ ░ ░▒▓███▀▒░ ▒░ ░ ░ ░▒ ▒ ▒▓▒▒░ ░░ ▒░ ░ ▒ ░░ ▒░▒ ░ ░ ░ ░ ░ ░ ▒ ░▒░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ Permissions: MegaStash.Upgrade (Allows Upgrading Stash On Hammer Hits) Console CMD: megastash.clear (Clears Data File, All Stashes Reset To 6 Slots(Items will eject on open if over slot amount)) */ using Facepunch; using Newtonsoft.Json; using Oxide.Core; using Oxide.Core.Plugins; using System; using System.Collections.Generic; using System.Linq; namespace Oxide.Plugins { [Info("MegaStash", "bmgjet", "1.0.3")] [Description("Adds larger storage to stashes")] class MegaStash : RustPlugin { //Extenal Plugins [PluginReference] private Plugin ServerRewards, Economics; //Data File StoredData storedData; #region Classes public class StoredData { public Dictionary SlotData = new Dictionary(); } //data file public class ResourcesData //Resources Layout { public string Shortname; public int Amount; public ulong SkinID; public string Name; public ResourcesData init(string s, int a, ulong i, string n) { Shortname = s; Name = n; Amount = a; SkinID = i; return this; } } #endregion #region Configuration private Configuration config; private class Configuration { [JsonProperty("Chat Message Name")] public string StashName = "MegaStash"; [JsonProperty("Chat Message Icon (SteamID)")] public string AnnouncementIcon = "76561199126605849"; [JsonProperty("Upgrade Sound Effect")] public string SoundEffect = "assets/bundled/prefabs/fx/repairbench/itemrepair.prefab"; [JsonProperty("Start Slot Amount")] public byte StartingSlots = 6; [JsonProperty("Upgrade Cost Type (serverrewards, economics, resources, free)")] public string Costtype = "resources"; [JsonProperty("Upgrade Cost For (serverrewards, economics)")] public float UpgradeCost = 50; [JsonProperty("Upgrade Currency Symbol For (serverrewards, economics)")] public string CurrencySymbol = "$"; [JsonProperty("Upgrade Cost When Using Resources")] public ResourcesData[] UpgradeCostResources = new ResourcesData[] { new ResourcesData().init("scrap", 5, 0, ""), new ResourcesData().init("cloth", 5, 0, ""), }; public string ToJson() => JsonConvert.SerializeObject(this); public Dictionary ToDictionary() => JsonConvert.DeserializeObject>(ToJson()); } protected override void LoadDefaultConfig() { config = new Configuration(); } protected override void LoadConfig() { base.LoadConfig(); try { config = Config.ReadObject(); if (config == null) { throw new JsonException(); } if (!config.ToDictionary().Keys.SequenceEqual(Config.ToDictionary(x => x.Key, x => x.Value).Keys)) { PrintWarning("Configuration appears to be outdated; updating and saving"); SaveConfig(); } } catch { PrintWarning($"Configuration file {Name}.json is invalid; using defaults"); LoadDefaultConfig(); } } protected override void SaveConfig() { PrintWarning($"Configuration changes saved to {Name}.json"); Config.WriteObject(config, true); } #endregion Configuration #region Language protected override void LoadDefaultMessages() { lang.RegisterMessages(new Dictionary { {"Upgraded", "Upgraded Stash!"}, {"NeedMore", "You need more resources:\n{0}"}, {"NoServerRewards", "ServerRewards not installed"}, {"Afford", "You can't afford to upgrade"}, {"NoEconomics", "Economics not installed"}, {"NotSupported", "Currency Type Not supported"}, {"Paid", "Paid {0} for upgrade"}, {"Bought", "Bought upgrade"}, {"AtMax", "Already at max slots!"}, }, this); } private string message(BasePlayer player, string key, params object[] args) { if (player == null) { return string.Format(lang.GetMessage(key, this), args); } return string.Format(lang.GetMessage(key, this, player.UserIDString), args); } private void MessageIcon(BasePlayer player, string txt, params object[] args) { rust.SendChatMessage(player, config.StashName, message(player, txt, args), config.AnnouncementIcon); } #endregion #region Oxide Hooks [ConsoleCommand("megastash.clear")] private void ClearMegaStashDataFile(ConsoleSystem.Arg arg) { if (arg.IsAdmin) { storedData.SlotData.Clear(); SaveData(); arg.ReplyWith("MegaStash Data Reset!"); } } private void Init() { permission.RegisterPermission("MegaStash.Upgrade", this); storedData = Interface.Oxide.DataFileSystem.ReadObject("MegaStash"); } private void CanLootEntity(BasePlayer player, StorageContainer container) { if (container.prefabID == 2568831788) //MegaStash { if (!storedData.SlotData.ContainsKey(container.net.ID.Value)) { storedData.SlotData.Add(container.net.ID.Value, config.StartingSlots); } container.inventory.capacity = storedData.SlotData[container.net.ID.Value]; container.SendNetworkUpdateImmediate(); if (container.inventory.itemList.Count > container.inventory.capacity) //Has more items then slots so dump excess items { for (int i = container.inventory.itemList.Count - 1; i >= 0; i--) { if (container.inventory.itemList.Count == container.inventory.capacity) { return; } container.inventory.itemList[i].DropAndTossUpwards(player.transform.position); container.inventory.MarkDirty(); } } } } private void OnHammerHit(BasePlayer ownerPlayer, HitInfo info) { if (info == null || info.HitEntity == null || info?.Initiator?.ToPlayer() == null) { return; } if (permission.UserHasPermission(info.Initiator.ToPlayer().UserIDString, "MegaStash.Upgrade") && info.HitEntity.prefabID == 2568831788) { if (!storedData.SlotData.ContainsKey(info.HitEntity.net.ID.Value)) { storedData.SlotData.Add(info.HitEntity.net.ID.Value, config.StartingSlots); } if (storedData.SlotData[info.HitEntity.net.ID.Value] >= 48) { MessageIcon(info.Initiator.ToPlayer(), "AtMax"); return; } if (CanUpgrade(info?.Initiator?.ToPlayer())) { storedData.SlotData[info.HitEntity.net.ID.Value]++; if (!string.IsNullOrEmpty(config.SoundEffect)) { Effect.server.Run(config.SoundEffect, info.HitEntity.transform.position); } SaveData(); } } } #endregion #region Methods private bool CanUpgrade(BasePlayer player) { object result = null; if (config.Costtype == "serverrewards") { if (ServerRewards == null) { MessageIcon(player, "NoServerRewards"); return false; } result = ServerRewards.Call("CheckPoints", player.UserIDString); if (result is int && (int)result <= (int)config.UpgradeCost) { MessageIcon(player, "Afford"); return false; } result = ServerRewards.Call("TakePoints", player.UserIDString, (int)config.UpgradeCost); } else if (config.Costtype == "economics") { if (Economics == null) { MessageIcon(player, "NoEconomics"); return false; } result = Economics.Call("Withdraw", player.UserIDString, (double)config.UpgradeCost); } else if (config.Costtype == "resources") { return HaveResources(player); } else if (config.Costtype == "free") { MessageIcon(player, "Upgraded"); return true; } else { MessageIcon(player, "NotSupported"); return false; } if (result is not bool val || !val) { MessageIcon(player, "Afford"); return false; } MessageIcon(player, "Paid", config.CurrencySymbol + config.UpgradeCost.ToString()); return true; } private bool HaveResources(BasePlayer player) { Dictionary Needed = new Dictionary(); //Check has needed meterials foreach (var component in config.UpgradeCostResources) { string name = component.Shortname; if (component.SkinID != 0) { int found = 0; List list = Pool.Get>(); player.inventory.GetAllItems(list); foreach (Item i in list) { if (i.skin == component.SkinID) { found += i.amount; } } Pool.FreeUnmanaged(ref list); if (found < component.Amount) { if (!Needed.ContainsKey(component.Name)) { Needed.Add(component.Name, 0); } Needed[component.Name] += component.Amount; } } else { if (player.inventory.GetAmount(ItemManager.FindItemDefinition(component.Shortname).itemid) < component.Amount) { if (!Needed.ContainsKey(name)) { Needed.Add(name, 0); } Needed[name] += component.Amount; } } } //Has everything needed so remove from player and allow if (Needed.Count == 0) { foreach (var item in config.UpgradeCostResources) { if (item.SkinID == 0) { Take(player, ItemManager.FindItemDefinition(item.Shortname).itemid, item.Amount); } else { int take = 0; List list = Pool.Get>(); player.inventory.GetAllItems(list); foreach (Item i in list) { if (i.skin == item.SkinID) { if (i.amount + take == item.Amount) { take += i.amount; i.Remove(); i.MarkDirty(); } else if (i.amount + take < item.Amount) { take += i.amount; i.Remove(); i.MarkDirty(); } else if (i.amount + take > item.Amount) { int amountremove = (item.Amount - take); i.amount -= amountremove; take += amountremove; i.MarkDirty(); } if (take == item.Amount) { break; } } } Pool.FreeUnmanaged(ref list); } } MessageIcon(player, "Bought"); return true; } //Doesnt have everything needed, build list and message. else { string text = ""; foreach (var item in Needed) { text += $" * {item.Key} x{item.Value}\n"; } rust.SendChatMessage(player, config.StashName, message(player, "NeedMore", text), config.AnnouncementIcon); return false; } } private void Take(BasePlayer player, int itemid, int amount) { var collect = Facepunch.Pool.Get>(); player.inventory.Take(collect, itemid, amount); // Take only calls RemoveFromContainer foreach (Item item in collect) { item.Remove(); } Facepunch.Pool.FreeUnmanaged(ref collect); } private void SaveData() { Interface.Oxide.DataFileSystem.WriteObject("MegaStash", storedData); } #endregion } }