public static void SendKitMatches(this TSPlayer player, List <Kit> matches) { if (matches.Count < 1) { player.SendSuccessMessage($"{Tag} No kits matched."); } else { player.SendSuccessMessage($"{Tag} Kit matches (use -k [kit] for more info):"); foreach (Kit k in matches) { string itemPreview = String.Join(", ", k.items.Select(i => i.GetName())).Substring(0, 50 - k.name.Length); player.SendInfoMessage($"{Tag} [{BankMain.FormatMoney(k.cost)}] {k.name}: {itemPreview}"); } } }
public static void SendItemMatches(this TSPlayer player, List <SItem> matches) { if (matches.Count < 1) { player.SendSuccessMessage($"{Tag} No items matched."); } else { player.SendSuccessMessage($"{Tag} Item matches:"); foreach (SItem i in matches) { string prefix = i.prefix > 0 ? i.GetPrefixName() + " " : ""; player.SendInfoMessage($"{Tag} " + $"[{BankMain.FormatMoney(i.cost)}] {prefix}{i.GetName()} x{i.stack}"); } } }
private static void purchase(BankLog log, BankAccount account, string item, int cost) { log.Write($"{account.AccountName} bought {item} for {BankMain.FormatMoney(cost)}"); }
public static async void Shop(CommandArgs args) { var regex = new Regex(@"^\w+ (?<Switch>\S+)\S* *(?:""?(?<Object>.+?)""?)?(?: (?<Digit>\d+))?$"); Match match = regex.Match(args.Message); if (!match.Success) { args.Player.SendInfoMessage($"{Tag} Syntax: {specifier}shop [-switch]"); var switches = new List <string>(); if (args.Player.Group.HasPermission(Permissions.Buy)) { switches.Add("-b/buy"); } if (args.Player.Group.HasPermission(Permissions.KitsBuy)) { switches.Add("-k/kits"); } if (args.Player.Group.HasPermission(Permissions.Help)) { switches.Add("-h/help [cmd]"); } if (args.Player.Group.HasPermission(Permissions.Search)) { switches.Add("-s/search"); } if (args.Player.Group.HasPermission(Permissions.Reload)) { switches.Add("-r/reload"); } args.Player.SendInfoMessage($"{Tag} Switches: {String.Join(" ", switches)}."); } else { SItem item; Kit kit; BankAccount account; int digit; switch (match.Groups["Switch"].Value.ToLowerInvariant()) { #region B (Purchase an item) case "-b": case "buy": if (!args.Player.Group.HasPermission(Permissions.Buy)) { args.Player.SendErrorMessage("You do not have access to this command."); return; } string itemName = match.Groups["Object"].Value; if (String.IsNullOrWhiteSpace(itemName)) { args.Player.SendErrorMessage($"{Tag} Invalid syntax! Proper syntax: {specifier}shop -b <item name | ID> [amount]"); return; } if (itemName.Equals("list", StringComparison.OrdinalIgnoreCase)) { IEnumerable <string> dataToPaginate = PaginationTools.BuildLinesFromTerms(Manager.GetItems().Select(i => i.GetName())); digit = 1; if (!String.IsNullOrWhiteSpace(match.Groups["Digit"].Value) && !Int32.TryParse(match.Groups["Digit"].Value, out digit)) { args.Player.SendErrorMessage($"{Tag} Invalid page number!"); return; } PaginationTools.SendPage(args.Player, digit, dataToPaginate.ToList(), new PaginationTools.Settings() { HeaderFormat = $"{Tag} Items ({{0}}/{{1}}):", FooterFormat = $"{Tag} Type {specifier}shop -b list {{0}} for more.", NothingToDisplayString = $"{Tag} No items available." }); return; } List <SItem> matches; try { matches = await Manager.GetMatchingItems(itemName); } catch (InvalidItemException) { args.Player.SendErrorMessage($"{Tag} Invalid item!"); return; } if (matches.Count != 1) { args.Player.SendItemMatches(matches); } else { item = matches[0]; digit = 1; if ((account = await BankMain.Bank.GetAsync(args.Player.User?.Name)) == null) { args.Player.SendErrorMessage($"{Tag} You must have a bank account to use this command."); } else if (!String.IsNullOrWhiteSpace(match.Groups["Digit"].Value) && !Int32.TryParse(match.Groups["Digit"].Value, out digit)) { args.Player.SendErrorMessage($"{Tag} Invalid amount!"); } else if (account.Balance < item.cost * digit) { args.Player.SendErrorMessage($"{Tag} You're {BankMain.FormatMoney(item.cost * digit - account.Balance)} short!"); } else if (!args.Player.InventorySlotAvailable) { args.Player.SendErrorMessage($"{Tag} Your inventory seems full."); } else { try { int stack = item.stack * digit; int cost = item.cost * digit; Item realItem = item.GetItem(); if (realItem.maxStack == 1 && stack > 1) { stack = 1; cost = item.cost; } else if (stack > realItem.maxStack) { args.Player.SendErrorMessage($"{Tag} You can't buy {stack} {realItem.name} at once."); return; } if (CShop.Config.UseGiveItemSSC) { args.Player.GiveItemSSC(item.netID, stack, item.prefix); } else { args.Player.GiveItem(item.netID, realItem.name, 2, 3, stack, item.prefix); } await BankMain.Bank.ChangeByAsync(account.AccountName, -cost); BankMain.Log.ItemPurchase(account, new SItem(item.netID, stack, cost, item.prefix)); string prefix = item.prefix > 0 ? item.GetPrefixName() + " " : ""; args.Player.SendSuccessMessage($"{Tag} Bought {stack} {prefix}{item.GetName()} for {BankMain.FormatMoney(cost)}."); } catch (NullReferenceException) { args.Player.SendErrorMessage($"{Tag} Invalid bank account!"); } catch (InvalidOperationException) { args.Player.SendErrorMessage($"{Tag} Error performing transaction. Possible database corruption."); args.Player.SendInfoMessage($"{Tag} Double check if there are multiple accounts with the same ID."); args.Player.SendInfoMessage($"{Tag} You can try syncing the server with the database by using the reload command."); } catch (BankLogException ex) { TShock.Log.Error(ex.ToString()); } } } return; #endregion #region H (Help -.-) case "-h": case "help": if (!args.Player.Group.HasPermission(Permissions.Help)) { args.Player.SendErrorMessage("You do not have access to this command."); return; } string helpString = match.Groups["Object"].Value; var helpLines = new List <string>(); if (String.IsNullOrWhiteSpace(helpString) || helpString.ToLowerInvariant() == "all") { helpLines.Add($"{TShock.Utils.ColorTag("CurrencyShop", new Color(90, 138, 211))} v{Instance.Version}" + $" by {TShock.Utils.ColorTag(Instance.Author, new Color(0, 127, 255))}"); helpLines.Add($"Available commands: {specifier}cshop <switch> [item | kit] [number]"); helpLines.Add("Switches: -b (buy) -k (buy kits) -h [cmd] (help) -s (search) -r (reload)"); helpLines.Add($"Type {specifier}shop -h [switch] for more."); if (args.Player.RealPlayer) { // This color looks like this: http://www.colorcombos.com/images/colors/993366.png helpLines.ForEach(l => args.Player.SendMessage(l, new Color(153, 51, 102))); } else { // Colors break when sending to console :( helpLines.ForEach(l => args.Player.SendInfoMessage(l)); } } else { // Now that I'm sure helpString is not null, let me lower it, for god's sake... helpString = helpString.ToLowerInvariant(); if (helpString.StartsWith("b")) { // Doco buy command helpLines.Add($"{Tag} Syntax: {specifier}shop -b[uy] <item name or id> [amount]"); helpLines.Add($"{Tag} Purchase an item from the shop inventory."); helpLines.Add($"{Tag} If 'amount' is given, it will be multiplied by the item's stack."); helpLines.Add($"{Tag} Type '{specifier}shop -b list' to get a list of all available items."); } else if (helpString.StartsWith("c") || helpString.StartsWith("k")) { // Doco kits command helpLines.Add($"{Tag} Syntax: {specifier}shop -k[it] <list | kit name> [confirm:1]"); helpLines.Add($"{Tag} Get information about one of the available item kits."); helpLines.Add($"{Tag} To buy a kit, type '{specifier}shop -k <kit name> 1' (you can only purchase one kit at once)."); helpLines.Add($"{Tag} Type '{specifier}shop -k list' to get a list of all available kits."); } else if (helpString.StartsWith("s")) { // Doco search command helpLines.Add($"{Tag} Syntax: {specifier}shop -s[earch] [item: | kit:] <text>"); helpLines.Add($"{Tag} Search for an item or kit which name starts with 'text'."); helpLines.Add($"{Tag} If 'text' matches one item, this will also search for any kits containing said item."); helpLines.Add($"{Tag} You can use 'item:' or 'kit:' before 'text' to search only for items or kits, respectively."); } else if (helpString.StartsWith("r")) { //Doco reload command helpLines.Add($"{Tag} Syntax: {specifier}shop -r[eload] <config | inventory>"); helpLines.Add($"{Tag} Reloads CurrencyBank's config file."); } else { args.Player.SendErrorMessage($"{Tag} Invalid switch! Type '{specifier}shop -h all' for a list of switches."); return; } // Finally, send the help data to the player helpLines.ForEach(l => args.Player.SendInfoMessage(l)); } return; #endregion #region K (Purchase a kit) case "-c": case "-k": case "kit": case "kits": if (!args.Player.Group.HasPermission(Permissions.KitsBuy)) { args.Player.SendErrorMessage("You do not have access to this command."); return; } string kitName = match.Groups["Object"].Value; if (String.IsNullOrWhiteSpace(kitName)) { args.Player.SendErrorMessage($"{Tag} Invalid syntax! Proper syntax: {specifier}shop -k <kit name> [confirm:1]"); return; } if (kitName.Equals("list", StringComparison.OrdinalIgnoreCase)) { IEnumerable <string> dataToPaginate = PaginationTools.BuildLinesFromTerms(Manager.GetKits().Select(k => k.name)); digit = 1; if (!String.IsNullOrWhiteSpace(match.Groups["Digit"].Value) && !Int32.TryParse(match.Groups["Digit"].Value, out digit)) { args.Player.SendErrorMessage($"{Tag} Invalid page number!"); return; } PaginationTools.SendPage(args.Player, digit, dataToPaginate.ToList(), new PaginationTools.Settings() { HeaderFormat = $"{Tag} Kits ({{0}}/{{1}}):", FooterFormat = $"{Tag} Type {specifier}shop -k list {{0}} for more.", NothingToDisplayString = $"{Tag} No kits available." }); return; } List <Kit> kitMatches = await Manager.GetMatchingKits(kitName); if (kitMatches.Count != 1) { args.Player.SendKitMatches(kitMatches); } else { kit = kitMatches[0]; if (String.IsNullOrWhiteSpace(match.Groups["Digit"].Value) || !Int32.TryParse(match.Groups["Digit"].Value, out digit) || digit < 1) { // Inform the player about the kit's contents args.Player.SendSuccessMessage($"{Tag} You have selected the kit '{kit.name}'."); args.Player.SendSuccessMessage($"{Tag} Kit's contents:"); string prefix = ""; foreach (SItem i in kit.items) { prefix = i.prefix > 0 ? i.GetPrefixName() + " " : ""; args.Player.SendInfoMessage($"{Tag} - {prefix}{i.GetName()} x{i.stack}"); } args.Player.SendInfoMessage($"{Tag} Type '{specifier}shop -k {kit.name} 1' to confirm your purchase."); } else if ((account = await BankMain.Bank.GetAsync(args.Player.User?.Name)) == null) { args.Player.SendErrorMessage($"{Tag} You must have a bank account to use this command."); } else if (account.Balance < kit.cost) { args.Player.SendErrorMessage($"{Tag} You're {BankMain.FormatMoney(kit.cost - account.Balance)} short!"); } else if (args.Player.GetEmptyInventorySlots().Count < kit.items.Count) { args.Player.SendErrorMessage($"{Tag} You must have {kit.items.Count} free inventory slots to purchase this kit."); } else { try { await BankMain.Bank.ChangeByAsync(account.AccountName, -kit.cost); BankMain.Log.KitPurchase(account, kit); foreach (SItem i in kit.items) { if (CShop.Config.UseGiveItemSSC) { args.Player.GiveItemSSC(i.netID, i.stack, i.prefix); } else { args.Player.GiveItem(i.netID, i.GetName(), 2, 3, i.stack, i.prefix); } } args.Player.SendSuccessMessage($"{Tag} Bought the '{kit.name}' kit for {BankMain.FormatMoney(kit.cost)}."); } catch (NullReferenceException) { args.Player.SendErrorMessage($"{Tag} Invalid bank account!"); } catch (InvalidOperationException) { args.Player.SendErrorMessage($"{Tag} Error performing transaction. Possible database corruption."); args.Player.SendInfoMessage($"{Tag} Double check if there are multiple accounts with the same ID."); args.Player.SendInfoMessage($"{Tag} You can try syncing the server with the database by using the reload command."); } catch (BankLogException ex) { TShock.Log.Error(ex.ToString()); } } } return; #endregion #region R (Reload config / inventory) case "-r": case "reload": if (!args.Player.Group.HasPermission(Permissions.Reload)) { args.Player.SendErrorMessage("You do not have access to this command."); return; } string reloadType = match.Groups["Object"].Value; try { if (String.IsNullOrWhiteSpace(reloadType) || reloadType.ToLower() == "all") { CShop.Config = Config.Read(Path.Combine(TShock.SavePath, "CurrencyBank", "Shop.json")); Manager.Reload(); args.Player.SendSuccessMessage($"{Tag} Reloaded config and inventory!"); } else if (reloadType.ToLower() == "config") { CShop.Config = Config.Read(Path.Combine(TShock.SavePath, "CurrencyBank", "Shop.json")); args.Player.SendSuccessMessage($"{Tag} Reloaded config!"); } else if (reloadType.ToLower().StartsWith("inv")) { Manager.Reload(); args.Player.SendSuccessMessage($"{Tag} Reloaded shop inventory!"); } else { args.Player.SendErrorMessage($"{Tag} Invalid reload type! Available types: config, inventory"); } } catch (Exception ex) { args.Player.SendErrorMessage($"{Tag} Something went wrong while reloading data. Check logs for details."); TShock.Log.Error(ex.ToString()); } return; #endregion #region S (Search for items and categories) case "-s": case "search": if (!args.Player.Group.HasPermission(Permissions.Search)) { args.Player.SendErrorMessage("You do not have access to this command."); return; } string searchString = match.Groups["Object"].Value; if (String.IsNullOrWhiteSpace(searchString)) { args.Player.SendErrorMessage($"{Tag} Invalid syntax! Proper syntax: {specifier}shop -s [search term...]"); return; } /* * Group 1 - Whether the user is looking for an item (term) * Group 2 - Whether the user is looking for a kit (term) * Group 3 - The item/kit to look for (search) */ Regex searchRegex = new Regex(@"^(?:(?<IsItem>i(?:tem)?:)|(?<IsKit>k(?:it)?:))? *(?<Object>.+)$"); Match searchMatch = searchRegex.Match(searchString); bool itemOnly = !String.IsNullOrWhiteSpace(searchMatch.Groups["IsItem"].Value); bool kitOnly = !String.IsNullOrWhiteSpace(searchMatch.Groups["IsKit"].Value); string searchName = searchMatch.Groups["Object"].Value; if (itemOnly) { // List all items on sale starting with the search string args.Player.SendInfoMessage($"{Tag} Searching for all items starting with '{searchName}'..."); try { args.Player.SendItemMatches(await Manager.GetMatchingItems(searchName)); } catch (InvalidItemException) { args.Player.SendSuccessMessage($"{Tag} No items matched."); } } else if (kitOnly) { // List all kits on sale containing an item List <Item> items = TShock.Utils.GetItemByName(searchName); if (items.Count == 1) { // Display all kits containing this item args.Player.SendInfoMessage($"{Tag} Searching for all kits containing the item '{items[0].name}'..."); args.Player.SendKitMatches(await Manager.KitContains(items[0].netID)); } else { // List all kits on sale starting with the search string args.Player.SendInfoMessage($"{Tag} Searching for all kits starting with '{searchName}'..."); args.Player.SendKitMatches(await Manager.GetMatchingKits(searchName)); } } else { // List everything on sale starting with the search string args.Player.SendInfoMessage($"{Tag} Searching for anything in stock starting with '{searchName}'..."); try { args.Player.SendItemMatches(await Manager.GetMatchingItems(searchName)); } catch (InvalidItemException) { args.Player.SendSuccessMessage($"{Tag} No items matched."); } List <Item> items = TShock.Utils.GetItemByName(searchName); if (items.Count == 1) { args.Player.SendKitMatches(await Manager.KitContains(items[0].netID)); } else { args.Player.SendKitMatches(await Manager.GetMatchingKits(searchName)); } } return; #endregion default: args.Player.SendErrorMessage($"{Tag} Invalid switch!"); args.Player.SendErrorMessage($"{Tag} Valid switches: -b (buy) -k (buy kits) -h [cmd] (help) -s (search) -r (reload)"); return; } } }