From dc825ad776f9fe9f763267874f6fa70c4870fc46 Mon Sep 17 00:00:00 2001 From: davidovski Date: Wed, 15 Oct 2025 04:01:15 +0100 Subject: v5 --- src/main/java/net/uomc/mineshaft/DailyCommand.java | 3 +- .../java/net/uomc/mineshaft/EnchantCommand.java | 64 +++++++--- src/main/java/net/uomc/mineshaft/FishCommand.java | 10 +- .../java/net/uomc/mineshaft/FurnaceCommand.java | 4 +- src/main/java/net/uomc/mineshaft/MineCommand.java | 135 +++++++++++++++------ src/main/java/net/uomc/mineshaft/Mineshaft.java | 105 ++++++++++++---- .../java/net/uomc/mineshaft/MineshaftItem.java | 57 +++++---- .../java/net/uomc/mineshaft/PickaxeCommand.java | 17 +-- src/main/java/net/uomc/mineshaft/Pickaxes.java | 122 +++++++++++++++++-- src/main/java/net/uomc/mineshaft/RobCommand.java | 7 +- .../java/net/uomc/mineshaft/crafting/Crafting.java | 68 ++++++++++- .../uomc/mineshaft/crafting/CraftingRecipe.java | 21 ++++ .../net/uomc/mineshaft/resources/Resource.java | 2 +- .../uomc/mineshaft/resources/ResourceManager.java | 9 ++ .../resources/commands/GiveResourcesCommand.java | 112 +++++++++-------- .../resources/commands/ValuesCommand.java | 7 +- .../mineshaft/resources/market/MarketCommand.java | 62 ++++++---- .../mineshaft/resources/market/MarketManager.java | 86 ++++++++----- .../net/uomc/mineshaft/resources/market/Offer.java | 2 +- 19 files changed, 649 insertions(+), 244 deletions(-) (limited to 'src/main/java/net') diff --git a/src/main/java/net/uomc/mineshaft/DailyCommand.java b/src/main/java/net/uomc/mineshaft/DailyCommand.java index fc814d1..129c336 100644 --- a/src/main/java/net/uomc/mineshaft/DailyCommand.java +++ b/src/main/java/net/uomc/mineshaft/DailyCommand.java @@ -29,12 +29,13 @@ public class DailyCommand extends CooldownCommand { award = bot.sumItems(award, bot.getMineCommand().getAwards(e.getMember(), bot.getMineCommand().getOre( - bot.getPickaxes().getPickaxeLevel(e.getMember())))); + e.getMember()))); } ; String awardsList = bot.createItemList(award, "+%s", ", "); bot.sendSuccessMessage(e, "You received your daily ores:\n**" + awardsList +"**"); + bot.addItems(e.getMember(), award); return true; } } diff --git a/src/main/java/net/uomc/mineshaft/EnchantCommand.java b/src/main/java/net/uomc/mineshaft/EnchantCommand.java index f85c92b..f147636 100644 --- a/src/main/java/net/uomc/mineshaft/EnchantCommand.java +++ b/src/main/java/net/uomc/mineshaft/EnchantCommand.java @@ -15,7 +15,7 @@ public class EnchantCommand extends DetailedCommand { private static final String COMMAND_IMAGE = "https://minecraft.wiki/images/Enchanting_Table.gif"; private static final double MIN_DISCOUNT = 0.4; - private static final double MAX_BOOKSHELVES = 24; + private static final long MAX_BOOKSHELVES = 24; private static final String COMMAND_TITLE = "Enchanting Table"; Mineshaft bot; @@ -42,20 +42,20 @@ public class EnchantCommand extends DetailedCommand { } int fortune = bot.getPickaxes().getPickaxeFortune(e.getMember()); + int efficiency = bot.getPickaxes().getPickaxeEfficiency(e.getMember()); long bookshelves = bot.getItem(e.getMember(), MineshaftItem.BOOKSHELF); String bookshelfDiscountPercent = "-" + (int) Math.ceil((1 -bookshelfDiscount(bookshelves))*100) + "%"; - long xpLevel = getXpLevel(fortune, bookshelves); - long lapisLevel = getLapisLevel(fortune, bookshelves); - long xpLevelNormal = getXpLevel(fortune, 0); - long lapisLevelNormal = getLapisLevel(fortune, 0); + long xpLevel = getXpLevel(fortune+efficiency, bookshelves); + long lapisLevel = getLapisLevel(fortune+efficiency, bookshelves); - String curr = ""; - if (fortune > 0) { - curr = "Your pickaxe has **Fortune " + Pickaxes.getRomanNumber(fortune) + "**\n\n"; - } + long xpLevelNormal = getXpLevel(fortune+efficiency, 0); + long lapisLevelNormal = getLapisLevel(fortune+efficiency, 0); + + String curr = "Your pickaxe " + getPickaxeEnchantmentsString(fortune, efficiency); + curr += "\n\n"; - String description = curr + "Enchant your pickaxe with `" + b.getPrefixManager().getPrefix(e.getGuild()) + "enchant fortune`\n\n"; + String description = curr + "Enchant your pickaxe with `" + b.getPrefixManager().getPrefix(e.getGuild()) + "enchant pickaxe`\n\n"; description += "**Cost:**\n"; @@ -89,24 +89,44 @@ public class EnchantCommand extends DetailedCommand { e.getMessage().replyEmbeds(em.build()).queue(); } + public String getPickaxeEnchantmentsString(int fortune, int efficiency) { + String curr = ""; + if (fortune > 0 || efficiency > 0) { + curr = "is enchanted with "; + if (fortune > 0) + curr += "**Fortune " + Pickaxes.getRomanNumber(fortune) + "** "; + if (efficiency > 0) + curr += "**Efficiency " + Pickaxes.getRomanNumber(efficiency) + "** "; + } else { + curr = "has no enchantments"; + } + return curr; + } + private long getLapisLevel(int fortune, long bookshelves) { return (long) (Math.pow(2, fortune + 4) * bookshelfDiscount(bookshelves)); } + private long getXpLevel(int fortune, long bookshelves) { + return (long) (15000l * Math.pow(fortune + 1, 2) * bookshelfDiscount(bookshelves)); + } + private double bookshelfDiscount(long bookshelves) { double b = Math.min(bookshelves, MAX_BOOKSHELVES); - return MIN_DISCOUNT + Math.log10( 1.0 + (9.0 * ((MAX_BOOKSHELVES - b) / MAX_BOOKSHELVES))) * MIN_DISCOUNT; + return MIN_DISCOUNT + Math.log( + 1.0 + ( (Math.E - 1) * ( + (double) (MAX_BOOKSHELVES - b) / (double) MAX_BOOKSHELVES)) + ) * (double) (1-MIN_DISCOUNT); } - private long getXpLevel(int fortune, long bookshelves) { - return (long) (15000l * Math.pow(fortune + 1, 2) * bookshelfDiscount(bookshelves)); - } private void enchant(MessageReceivedEvent e, String[] args) { int fortune = bot.getPickaxes().getPickaxeFortune(e.getMember()); + int efficiency = bot.getPickaxes().getPickaxeEfficiency(e.getMember()); + long bookshelves = bot.getItem(e.getMember(), MineshaftItem.BOOKSHELF); - long xpLevel = getXpLevel(fortune, bookshelves); - long lapisLevel = getLapisLevel(fortune, bookshelves); + long xpLevel = getXpLevel(fortune + efficiency, bookshelves); + long lapisLevel = getLapisLevel(fortune + efficiency, bookshelves); long memberLapis = bot.getItem(e.getMember(), MineshaftItem.LAPIS); long memberXp = bot.getItem(e.getMember(), MineshaftItem.XP); @@ -123,10 +143,16 @@ public class EnchantCommand extends DetailedCommand { bot.removeItem(e.getMember(), MineshaftItem.LAPIS, lapisLevel); bot.removeItem(e.getMember(), MineshaftItem.XP, xpLevel); - int level = bot.getPickaxes().incrementFortune(e.getMember()); - bot.sendSuccessMessage(e, ":white_check_mark: You enchanted your pickaxe. Now it has **Fortune " + Pickaxes.getRomanNumber(level) + "**"); + String newEnch = ""; + if (Math.random() > 0.5) { + int level = bot.getPickaxes().incrementFortune(e.getMember()); + newEnch = "**Fortune " + Pickaxes.getRomanNumber(level) + "**"; + } else { + int level = bot.getPickaxes().incrementEfficiency(e.getMember()); + newEnch = "**Efficiency " + Pickaxes.getRomanNumber(level) + "**"; + } + bot.sendSuccessMessage(e, ":white_check_mark: You enchanted your pickaxe. You now have " + newEnch); } - } diff --git a/src/main/java/net/uomc/mineshaft/FishCommand.java b/src/main/java/net/uomc/mineshaft/FishCommand.java index 3df7994..2eac218 100644 --- a/src/main/java/net/uomc/mineshaft/FishCommand.java +++ b/src/main/java/net/uomc/mineshaft/FishCommand.java @@ -25,6 +25,7 @@ import net.uomc.mineshaft.resources.ResourceManager; public class FishCommand extends CooldownCommand { private static final double XP_SPAWN_AMOUNT = 2000; private static final double BOOK_SPAWN_CHANCE = 0.05; + private static final double STRING_SPAWN_CHANCE = 0.5; private static long MIN_WAIT_MS = 1500; private static long MAX_WAIT_MS = 10000; @@ -41,6 +42,7 @@ public class FishCommand extends CooldownCommand { protected FishCommand(Mineshaft bot) { super(bot); setCooldown(20l * 1000l); + this.bot = bot; setDetails(CommandDetails.from("fish", "go fishing")); } @@ -49,7 +51,6 @@ public class FishCommand extends CooldownCommand { public boolean trigger(MessageReceivedEvent e) { e.getMessage().addReaction(Emoji.fromUnicode(EmojiParser.parseToUnicode(REACTION_FISH))).queue(); - double random = Math.random(); long waitTime = MIN_WAIT_MS + (long) (Math.random() * (MAX_WAIT_MS - MIN_WAIT_MS)); long reelTime = MIN_REEL_MS + (long) (Math.random() * (MAX_REEL_MS - MIN_REEL_MS)); @@ -99,12 +100,17 @@ public class FishCommand extends CooldownCommand { public Map getAwards(Member member) { Map award = new HashMap<>(); - if (Math.random() < BOOK_SPAWN_CHANCE) { + double random = Math.random(); + if (random < BOOK_SPAWN_CHANCE) { award.put(MineshaftItem.BOOK, 1l); + } else if (random < STRING_SPAWN_CHANCE) { + award.put(MineshaftItem.STRING, 8l); + award.put(MineshaftItem.XP, (long) Math.ceil(Math.random() * XP_SPAWN_AMOUNT * 0.5)); } else { award.put(MineshaftItem.FISH, Math.random() > 0.5 ? 1l : 2l); award.put(MineshaftItem.XP, (long) Math.ceil(Math.random() * XP_SPAWN_AMOUNT)); } + return award; } } diff --git a/src/main/java/net/uomc/mineshaft/FurnaceCommand.java b/src/main/java/net/uomc/mineshaft/FurnaceCommand.java index 8c2b628..9212ac6 100644 --- a/src/main/java/net/uomc/mineshaft/FurnaceCommand.java +++ b/src/main/java/net/uomc/mineshaft/FurnaceCommand.java @@ -36,9 +36,9 @@ public class FurnaceCommand extends CooldownCommand { public FurnaceCommand(Mineshaft bot) { super(bot); - setCommandDetails(CommandDetails.from("furnace", "get free ingots", "furnace")); + setCommandDetails(CommandDetails.from("furnace,furnaces,furn", "get free ingots", "furnace")); this.bot = bot; - setCooldown(60l * 60l * 1000l); + setCooldown(30l * 60l * 1000l); } @Override diff --git a/src/main/java/net/uomc/mineshaft/MineCommand.java b/src/main/java/net/uomc/mineshaft/MineCommand.java index ecee140..730ae85 100644 --- a/src/main/java/net/uomc/mineshaft/MineCommand.java +++ b/src/main/java/net/uomc/mineshaft/MineCommand.java @@ -46,9 +46,13 @@ public class MineCommand extends CooldownCommand { private static final double DIAMOND_SPAWN_AMOUNT = 1; private static final double OBSIDIAN_SPAWN_AMOUNT = 1; private static final double XP_SPAWN_AMOUNT = 1000; + private static final double QUARTZ_SPAWN_AMOUNT = 16; + private static final double SKULL_SPAWN_AMOUNT = 1; + private static final double NETHERITE_SPAWN_AMOUNT = 1; private Map ores; private List oresList; + private List netherOresList; private Mineshaft bot; @@ -57,14 +61,15 @@ public class MineCommand extends CooldownCommand { this.bot = bot; setCooldown(15l * 1000l); + setDetails(CommandDetails.from("mine", "mine diamonds")); this.ores = loadOreImages(); oresList = loadOreOrder(); + netherOresList = loadNetherOreOrder(); } public List loadOreOrder() { - // lololol no return List.of( "coal", "copper", @@ -74,10 +79,44 @@ public class MineCommand extends CooldownCommand { "gold", "diamond", "emerald", + "obsidian", "obsidian" ); } + public List loadNetherOreOrder() { + return List.of( + "quartz", + "quartz", + "quartz", + "quartz", + "gold", + "gold", + "skull", + "skull", + "netherite", + "netherite" + ); + } + + private int levelToMaxOre(int pickaxe) { + switch (pickaxe) { + case 0: // stone pickaxe + return 2; // copper + case 1: // copper pickaxe + return 4; // lapis + case 2: // iron pickaxe + return 6; // gold + case 3: // gold pickaxe + return 8; // diamond + case 4: // diamond pickaxe + return 9; // obsidian + case 5: // netherite pickaxe + return 10; // obsidian, 2 + } + return 9; + } + public Map loadOreImages() { Map ores = new LinkedHashMap(); JSONObject config = bot.getConfig(); @@ -94,12 +133,22 @@ public class MineCommand extends CooldownCommand { return ores; } - public MineshaftItem getOre(int pickaxe) { + public MineshaftItem getOre(Member m) { + return getOre(m, false); + } + + public MineshaftItem getOre(Member m, boolean nether) { + int pickaxe = bot.getPickaxes().getPickaxeLevel(m); double random = Math.random(); int maxOre = levelToMaxOre(pickaxe); - int i = (int) Math.floor(Math.pow(random, 2) * maxOre); - String oreName = oresList.get(i); + + List list = oresList; + if(nether) list = netherOresList; + + double c = getEfficiencyCurve(m); + int i = (int) Math.floor(Math.pow(random, c) * maxOre); + String oreName = list.get(i); MineshaftItem ore = MineshaftItem.valueOf(oreName.toUpperCase()); return ore; } @@ -107,34 +156,23 @@ public class MineCommand extends CooldownCommand { @Override public boolean trigger(MessageReceivedEvent e) { - int pickaxe = bot.getPickaxes().getPickaxeLevel(e.getMember()); - MineshaftItem ore = getOre(pickaxe); - int i = oresList.indexOf(ore.toString().toLowerCase()); + boolean nether = bot.getPickaxes().isNether(e.getMember()); + MineshaftItem ore = getOre(e.getMember(), nether); + int i; + if (nether) { + i = oresList.indexOf(ore.toString().toLowerCase()); + } else { + i = netherOresList.indexOf(ore.toString().toLowerCase()); + } - spawnDrop(e.getChannel(), ore, i, m -> {}); + spawnDrop(e.getChannel(), ore, i, nether, m -> {}); e.getMessage().addReaction(Emoji.fromUnicode(EmojiParser.parseToUnicode(":pick:"))).queue(); return true; } - private int levelToMaxOre(int pickaxe) { - switch (pickaxe) { - case 0: // stone pickaxe - return 2; // copper - case 1: // copper pickaxe - return 4; // lapis - case 2: // iron pickaxe - return 6; // gold - case 3: // gold pickaxe - return 8; // diamond - case 4: // diamond pickaxe - return 9; // obsidian - // TODO for obsidian u can make nether portal - } - return 9; - } - public void spawnDrop(MessageChannel channel, MineshaftItem ore, int oreLevel, Consumer then) { - sendDrop(channel, ore, m -> { + public void spawnDrop(MessageChannel channel, MineshaftItem ore, int oreLevel, boolean nether, Consumer then) { + sendDrop(channel, ore, nether, m -> { EventWaiter eventWaiter = new EventWaiter(); channel.getJDA().addEventListener(eventWaiter); @@ -155,14 +193,14 @@ public class MineCommand extends CooldownCommand { }); }, DROP_DURATION_SECONDS, TimeUnit.SECONDS, () -> { cleanup(channel, m, ore); - endDrop(m, ore); }); }); } public void cleanup(MessageChannel channel, Message message, MineshaftItem ore) { - message.delete().queue(); + + message.delete().queue(a -> {}, x -> {}); channel.getHistoryAfter(message, 100).queueAfter(5, TimeUnit.SECONDS, h -> { ArrayList msgs = new ArrayList(); @@ -176,11 +214,11 @@ public class MineCommand extends CooldownCommand { ; } - public void sendDrop(MessageChannel channel, MineshaftItem ore, Consumer callback) { + public void sendDrop(MessageChannel channel, MineshaftItem ore, boolean nether, Consumer callback) { EmbedBuilder embedBuilder = new EmbedBuilder(); embedBuilder.setColor(bot.getColor()); - embedBuilder.setImage(getOreUrl(ore)); + embedBuilder.setImage(getOreUrl(ore, nether)); embedBuilder.setTitle(String.format(DROP_TITLE)); embedBuilder.setDescription(String.format(DROP_DESCRIPTION, getPickString(ore), PeelingUtils.formatTimeRelativeFromNow(DROP_DURATION_SECONDS * 1000l))); @@ -195,10 +233,6 @@ public class MineCommand extends CooldownCommand { embedBuilder.setColor(bot.getColor()); Map awards = getAwards(member, ore); - int fortune = bot.getPickaxes().getPickaxeFortune(member); - if (fortune > 0) { - bot.multiply(awards, fortune + 1); - } bot.addItems(member, awards); String awardsList = bot.createItemList(awards, "+%s"); @@ -208,6 +242,7 @@ public class MineCommand extends CooldownCommand { channel.sendMessageEmbeds(embedBuilder.build()).queue(callback); } + public void endDrop(Message message, MineshaftItem ore) { EmbedBuilder embedBuilder = new EmbedBuilder(); @@ -221,8 +256,12 @@ public class MineCommand extends CooldownCommand { }); } - public String getOreUrl(MineshaftItem ore) { - String oreName = ore.toString(); + public String getOreUrl(MineshaftItem ore, boolean nether) { + String prefix = ""; + if (nether) + prefix = "nether_"; + + String oreName = prefix + ore.toString(); if (ores.containsKey(oreName)) return ores.get(oreName); @@ -262,6 +301,7 @@ public class MineCommand extends CooldownCommand { break; case EMERALD: award.put(MineshaftItem.EMERALD, (long) Math.ceil(Math.random() * EMERALD_SPAWN_AMOUNT)); + award.put(MineshaftItem.XP, (long) Math.ceil(Math.random() * XP_SPAWN_AMOUNT * 5l)); break; case DIAMOND: award.put(MineshaftItem.DIAMOND, (long) Math.ceil(Math.random() * DIAMOND_SPAWN_AMOUNT)); @@ -269,12 +309,33 @@ public class MineCommand extends CooldownCommand { break; case OBSIDIAN: award.put(MineshaftItem.OBSIDIAN, (long) Math.ceil(Math.random() * OBSIDIAN_SPAWN_AMOUNT)); + break; + case QUARTZ: + award.put(MineshaftItem.QUARTZ, (long) Math.ceil(Math.random() * QUARTZ_SPAWN_AMOUNT)); + award.put(MineshaftItem.XP, (long) Math.ceil(Math.random() * XP_SPAWN_AMOUNT * 5l)); + break; + case SKULL: + award.put(MineshaftItem.SKULL, (long) Math.ceil(Math.random() * SKULL_SPAWN_AMOUNT)); + award.put(MineshaftItem.XP, (long) Math.ceil(Math.random() * XP_SPAWN_AMOUNT * 10l)); + break; + case NETHERITE: + award.put(MineshaftItem.NETHERITE, (long) Math.ceil(Math.random() * NETHERITE_SPAWN_AMOUNT)); award.put(MineshaftItem.XP, (long) Math.ceil(Math.random() * XP_SPAWN_AMOUNT * 10l)); break; default: break; } + return bot.multiply(award, getPickaxeFortuneCurve(member)); + } + + public double getEfficiencyCurve(Member m) { + return 1 + Math.pow(0.5, bot.getPickaxes().getPickaxeEfficiency(m) / 2); - return award; } + private double getPickaxeFortuneCurve(Member m) { + int fortune = bot.getPickaxes().getPickaxeFortune(m); + return fortune + Math.pow(1.2, fortune + 1); + } + + } diff --git a/src/main/java/net/uomc/mineshaft/Mineshaft.java b/src/main/java/net/uomc/mineshaft/Mineshaft.java index ebdcf21..1584529 100644 --- a/src/main/java/net/uomc/mineshaft/Mineshaft.java +++ b/src/main/java/net/uomc/mineshaft/Mineshaft.java @@ -1,6 +1,9 @@ package net.uomc.mineshaft; import net.uomc.mineshaft.crafting.Crafting; +import net.uomc.mineshaft.farm.CompostCommand; +import net.uomc.mineshaft.farm.FarmCommand; +import net.uomc.mineshaft.farm.TradeCommand; import net.uomc.mineshaft.resources.Resource; import java.io.IOException; import java.util.Arrays; @@ -29,6 +32,7 @@ import com.mouldycheerio.dbot.util.PeelingUtils; import net.dv8tion.jda.api.entities.Member; import net.uomc.mineshaft.resources.ResourceManager; +import net.uomc.mineshaft.resources.market.MarketCommand; public class Mineshaft extends CustomBot { @@ -38,6 +42,7 @@ public class Mineshaft extends CustomBot { private Pickaxes pickaxes; private Crafting crafting; private MineCommand mineCommand; + private EnchantCommand enchantCommand; public Mineshaft(JSONObject config) throws LoginException, JSONException, IOException, InterruptedException { super(config); @@ -54,15 +59,21 @@ public class Mineshaft extends CustomBot { resourceManager = new ResourceManager(this); + getCommandController().addCommand(new MarketCommand(resourceManager.getMarketManager())); getCommandController().addCommand(new DailyCommand(this)); - getCommandController().addCommand(new EnchantCommand(this)); + + enchantCommand = new EnchantCommand(this); + getCommandController().addCommand(enchantCommand); getCommandController().addCommand(new FurnaceCommand(this)); getCommandController().addCommand(new PickaxeCommand(this)); + getCommandController().addCommand(new Portal(this)); + mineCommand = new MineCommand(this); getCommandController().addCommand(mineCommand); getCommandController().addCommand(new FishCommand(this)); getCommandController().addCommand(new RobCommand(this)); + getCommandController().addCommand(new TradeCommand(this)); getCommandController().removeCommand("help"); @@ -74,7 +85,7 @@ public class Mineshaft extends CustomBot { notes.append("Upgrade your **pickaxe** and find new ores `m!pickaxe`\n"); notes.append("**Craft** new items `m!craft`\n"); notes.append("Fight other players! `m!pvp`\n"); - notes.append("Share your resources `m!give`\n"); + notes.append("Trade your resources `m!market` and `m!give`\n"); notes.append("Become the **top** valuable player `m!top`\n"); notes.append("\nGet free **daily** ores with `m!daily`\n"); @@ -85,26 +96,59 @@ public class Mineshaft extends CustomBot { // TODO update when changes String title = "Patch Notes"; StringBuilder notes = new StringBuilder(); - notes.append("### v0.3.1\n"); - notes.append("- Added furnace crafting recipe\n"); - notes.append("- Added `m!daily` to get daily commands\n"); - notes.append("- Balanced amount of ores needed to upgrade pickaxe\n"); - notes.append("- Fix obsidian not spawning\n"); - notes.append("- Added `m!cooldowns`\n"); - notes.append("### v0.3\n"); - notes.append("- Added items for all ores `m!inventory`\n"); - notes.append("- Added pickaxe levels `m!pickaxe`\n"); - notes.append(" - Pickaxe can be upgraded, giving access to better ores (`m!pickaxe upgrade`)\n"); - notes.append("- Added enchanting `m!enchant`\n"); - notes.append(" - Your pickaxe can be enchanted by spending lapis and xp\n"); - notes.append(" - Owning bookshelves gives you a discount on the amount of levels it costs to enchant\n"); - notes.append("- Added crafting `m!craft`\n"); - notes.append(" - Enchanting table and books can now be crafted!\n"); - notes.append("- Fishing now drops books\n"); - notes.append("- Rob has been relaced with `m!kill`\n"); - notes.append(" - Killing a player will drop some of their items\n"); - notes.append("- Added obsidian\n"); - notes.append("- Removed `m!flip`, this will be added in a future update (with a new mechanic)\n"); + notes.append("### v0.5.2\n"); + notes.append("- Fix trader giving impossible item prices\n"); + notes.append("- Items can only be given to players who are in the same dimension\n"); + notes.append("### v0.5.1\n"); + notes.append("- Kill only works if you are in the same dimension as the other player\n"); + notes.append("- Farm cannot be accessed from the nether\n"); + notes.append("- Added `m!top pickaxes`\n"); + notes.append("### v0.5\n"); + notes.append("- Added compostor\n"); + notes.append(" - compost items with `m!compost`\n"); + notes.append(" - The more compostors you own, the more items you can compost at a time\n"); + notes.append("- Added farming `m!farm`\n"); + notes.append(" - Crops can be planted and harvested\n"); + notes.append(" - Size of farm can be expanded with bone meal\n"); + notes.append("- Added villager item\n"); + notes.append(" - Villagers allow you to trade with the wandering trader `m!trade`\n"); + notes.append("- Added Carrots, Potatos and Sugar cane\n"); + notes.append("- Added `m!top [item]` to list who has the most of an item\n"); + notes.append("- Fixed `m!daily`\n"); + notes.append("- Fixed typos\n"); + notes.append("### v0.4\n"); + notes.append("- Added nether\n"); + notes.append(" - 10 obsidian can now be used to craft a portal\n"); + notes.append(" - Nether spawns new ores \n"); + notes.append("- Netherite pickaxe is now achievable\n"); + notes.append("- Fishing will have a chance to give you string\n"); + notes.append("- String can be crafted into wool and beds\n"); + notes.append("- Added Efficiency enchantment\n"); + notes.append(" - Further increases spawn rates of rarer ores\n"); + notes.append("- Enchantments are now applied to `m!daily`'s loot\n"); + notes.append("- Furnace can now be accessed every 30 minutes\n"); + notes.append("- Added `m!market` for trading items\n"); + notes.append("- Fix `m!give` to work properly\n"); + //notes.append("### v0.3.1\n"); + //notes.append("- Added furnace crafting recipe\n"); + //notes.append("- Added `m!daily` to get daily commands\n"); + //notes.append("- Balanced amount of ores needed to upgrade pickaxe\n"); + //notes.append("- Fix obsidian not spawning\n"); + //notes.append("- Added `m!cooldowns`\n"); + //notes.append("### v0.3\n"); + //notes.append("- Added items for all ores `m!inventory`\n"); + //notes.append("- Added pickaxe levels `m!pickaxe`\n"); + //notes.append(" - Pickaxe can be upgraded, giving access to better ores (`m!pickaxe upgrade`)\n"); + //notes.append("- Added enchanting `m!enchant`\n"); + //notes.append(" - Your pickaxe can be enchanted by spending lapis and xp\n"); + //notes.append(" - Owning bookshelves gives you a discount on the amount of levels it costs to enchant\n"); + //notes.append("- Added crafting `m!craft`\n"); + //notes.append(" - Enchanting table and books can now be crafted!\n"); + //notes.append("- Fishing now drops books\n"); + //notes.append("- Rob has been relaced with `m!kill`\n"); + //notes.append(" - Killing a player will drop some of their items\n"); + //notes.append("- Added obsidian\n"); + //notes.append("- Removed `m!flip`, this will be added in a future update (with a new mechanic)\n"); sendMessage(e, title, notes.toString()); }); @@ -142,6 +186,15 @@ public class Mineshaft extends CustomBot { b.sendMessage(e, "Active cooldowns", cooldowns.toString()); }); + getCommandController().removeCommand("top"); + getCommandController().addCommand(new MineshaftLeaderBoardCommand(this)); + + getCommandController().removeCommand("give"); + getCommandController().addCommand(new MineshaftGiveResourcesCommand(this)); + + getCommandController().addCommand(new FarmCommand(this)); + getCommandController().addCommand(new CompostCommand(this)); + logger = new FullLogger(this); } @@ -269,4 +322,12 @@ public class Mineshaft extends CustomBot { return Collections.unmodifiableMap(lacking); } + + public Crafting getCrafting() { + return crafting; + } + + public EnchantCommand getEnchantCommand() { + return enchantCommand; + } } diff --git a/src/main/java/net/uomc/mineshaft/MineshaftItem.java b/src/main/java/net/uomc/mineshaft/MineshaftItem.java index 91a4957..8956b93 100644 --- a/src/main/java/net/uomc/mineshaft/MineshaftItem.java +++ b/src/main/java/net/uomc/mineshaft/MineshaftItem.java @@ -1,33 +1,46 @@ package net.uomc.mineshaft; public enum MineshaftItem { - COAL("coal"), - IRON("iron"), - COPPER("copper"), - LAPIS("lapis"), - REDSTONE("redstone"), - GOLD("gold"), - EMERALD("emerald"), - DIAMOND("diamond"), - NETHERITE("netherite"), - OBSIDIAN("obsidian"), - FISH("fish"), - BOOK("book"), - XP("xp"), - ENCHANTING_TABLE("enchanting_table"), - BOOKSHELF("bookshelf"), - FURNACE("furnace") + COAL, + IRON, + COPPER, + LAPIS, + REDSTONE, + GOLD, + EMERALD, + DIAMOND, + NETHERITE, + OBSIDIAN, + FISH, + BOOK, + XP, + ENCHANTING_TABLE, + BOOKSHELF, + FURNACE, + PORTAL, + QUARTZ, + SKULL, + STRING, + WOOL, + BED, + BEACON, + SLOT_MACHINE, + VILLAGER, + PAPER, + CANE, + CARROT, + POTATO, + COMPOSTER, + BONEMEAL, + IRON_FARM, ; - private final String text; - - MineshaftItem(String string) { - text = string; + MineshaftItem() { } @Override public String toString() { - return text; + return super.toString().toLowerCase(); } - + } diff --git a/src/main/java/net/uomc/mineshaft/PickaxeCommand.java b/src/main/java/net/uomc/mineshaft/PickaxeCommand.java index 6ca3e08..31ac11c 100644 --- a/src/main/java/net/uomc/mineshaft/PickaxeCommand.java +++ b/src/main/java/net/uomc/mineshaft/PickaxeCommand.java @@ -52,6 +52,7 @@ public class PickaxeCommand extends DetailedCommand { String nextPick = bot.getPickaxes().getNextPickaxeName(e.getMember()); String pickImage = bot.getPickaxes().getPickaxeImage(e.getMember()); int fortune = bot.getPickaxes().getPickaxeFortune(e.getMember()); + int efficiency = bot.getPickaxes().getPickaxeEfficiency(e.getMember()); Member target = PeelingUtils.getSingleMentionFromArgs(e); String p1 = target.equals(e.getMember()) ? "You currently have" : String.format("%s currently has", e.getMember().getEffectiveName()); @@ -65,11 +66,7 @@ public class PickaxeCommand extends DetailedCommand { upgradeString = ""; } - String enchants = String.format("\n*%s pickaxe has no enchantments*", p2); - if (fortune > 0) { - enchants = String.format("\n%s pickaxe is enchanted with **Fortune %s**", p2, - Pickaxes.getRomanNumber(fortune)); - } + String enchants = String.format("\n%s ", p2) + bot.getEnchantCommand().getPickaxeEnchantmentsString(fortune, efficiency); EmbedBuilder em = new EmbedBuilder(); em.setTitle(p2); @@ -87,23 +84,19 @@ public class PickaxeCommand extends DetailedCommand { switch ((int) level) { case 0: cost.put(MineshaftItem.COPPER, 16l); - //cost.put(MineshaftItem.XP, 5000l); break; case 1: cost.put(MineshaftItem.IRON, 32l); - //cost.put(MineshaftItem.XP, 10000l); break; case 2: - cost.put(MineshaftItem.GOLD, 48l); - //cost.put(MineshaftItem.XP, 64000l); + cost.put(MineshaftItem.GOLD, 64l); break; case 3: - cost.put(MineshaftItem.DIAMOND, 64l); - //cost.put(MineshaftItem.XP, 128000l); + cost.put(MineshaftItem.DIAMOND, 32l); break; case 4: - cost.put(MineshaftItem.DIAMOND, 9999999999999999l); + cost.put(MineshaftItem.NETHERITE, 128l); break; } diff --git a/src/main/java/net/uomc/mineshaft/Pickaxes.java b/src/main/java/net/uomc/mineshaft/Pickaxes.java index 42a1f92..16d6958 100644 --- a/src/main/java/net/uomc/mineshaft/Pickaxes.java +++ b/src/main/java/net/uomc/mineshaft/Pickaxes.java @@ -3,20 +3,27 @@ package net.uomc.mineshaft; import java.io.File; import java.sql.SQLException; import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; import org.json.JSONObject; import com.mouldycheerio.dbot.util.DatabaseUtils; import com.mouldycheerio.dbot.util.PeelingUtils; +import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; -class Pickaxes { +public class Pickaxes { private static final int MAX_PICKAXE_LEVEL = 5; private static final String LEVEL_TABLE = "levels"; private static final String FORTUNE_TABLE = "ench_fortune"; + private static final String EFFICIENCY_TABLE = "ench_efficiency"; + private static final String DIMENSION_TABLE = "dimension"; + + private static final String FARM_LEVEL_TABLE = "farm"; private String pickaxesDb; @@ -27,11 +34,45 @@ class Pickaxes { private void initDB() { try { - DatabaseUtils.createSimpleKVtable(pickaxesDb, LEVEL_TABLE); DatabaseUtils.createSimpleKVtable(pickaxesDb, FORTUNE_TABLE); } catch (SQLException e) { - // e.printStackTrace(); } + try { + DatabaseUtils.createSimpleKVtable(pickaxesDb, DIMENSION_TABLE); + } catch (SQLException e) { + } + try { + DatabaseUtils.createSimpleKVtable(pickaxesDb, EFFICIENCY_TABLE); + } catch (SQLException e) { + } + try { + DatabaseUtils.createSimpleKVtable(pickaxesDb, LEVEL_TABLE); + } catch (SQLException e) { + } + try { + DatabaseUtils.createSimpleKVtable(pickaxesDb, FARM_LEVEL_TABLE); + } catch (SQLException e) { + } + } + + public void setFarmLevel(Member member, long value) { + try { + DatabaseUtils.putInKVtable(pickaxesDb, FARM_LEVEL_TABLE, member.getId() + ":" + member.getGuild().getId(), value); + } catch (SQLException e) { + e.printStackTrace(); + } + } + public long getFarmLevel(String member, String guild) { + try { + return DatabaseUtils.getInKVtable(pickaxesDb, FARM_LEVEL_TABLE, member + ":" + guild); + } catch (SQLException e) { + e.printStackTrace(); + } + return 0l; + } + + public long getFarmLevel(Member member) { + return getFarmLevel(member.getId(), member.getGuild().getId()); } public void setLevel(Member member, long value) { @@ -42,15 +83,52 @@ class Pickaxes { } } + public long getLevel(String member, String guild) { + try { + return DatabaseUtils.getInKVtable(pickaxesDb, LEVEL_TABLE, member + ":" + guild); + } catch (SQLException e) { + e.printStackTrace(); + } + return 0l; + } + public long getLevel(Member member) { + return getLevel(member.getId(), member.getGuild().getId()); + } + public List getMembersGuilds() { + try { + return DatabaseUtils.listKeys(pickaxesDb, LEVEL_TABLE); + } catch (SQLException e) { + e.printStackTrace(); + } + return Collections.emptyList(); + } + + public List getMembers(Guild guild) { + return getMembersGuilds().stream().filter(m -> guild.getId().equals(m.split(":")[1])).map(m -> m.split(":")[0]).collect(Collectors.toList()); + } + + private void setEfficiency(Member member, long value) { try { - return DatabaseUtils.getInKVtable(pickaxesDb, LEVEL_TABLE, member.getId() + ":" + member.getGuild().getId()); + DatabaseUtils.putInKVtable(pickaxesDb, EFFICIENCY_TABLE, member.getId() + ":" + member.getGuild().getId(), value); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + public long getEfficiency(String member, String guild) { + try { + return DatabaseUtils.getInKVtable(pickaxesDb, EFFICIENCY_TABLE, member + ":" + guild); } catch (SQLException e) { e.printStackTrace(); } return 0l; } + public long getEfficiency(Member member) { + return getEfficiency(member.getId(), member.getGuild().getId()); + } + private void setFortune(Member member, long value) { try { DatabaseUtils.putInKVtable(pickaxesDb, FORTUNE_TABLE, member.getId() + ":" + member.getGuild().getId(), value); @@ -59,15 +137,36 @@ class Pickaxes { } } - private long getFortune(Member member) { + public long getFortune(String member, String guild) { try { - return DatabaseUtils.getInKVtable(pickaxesDb, FORTUNE_TABLE, member.getId() + ":" + member.getGuild().getId()); + return DatabaseUtils.getInKVtable(pickaxesDb, FORTUNE_TABLE, member + ":" + guild); } catch (SQLException e) { e.printStackTrace(); } return 0l; } + public long getFortune(Member member) { + return getFortune(member.getId(), member.getGuild().getId()); + } + + public void setNether(Member member, boolean nether) { + try { + DatabaseUtils.putInKVtable(pickaxesDb, DIMENSION_TABLE, member.getId() + ":" + member.getGuild().getId(), nether ? 1: 0); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + public boolean isNether(Member member) { + try { + return DatabaseUtils.getInKVtable(pickaxesDb, DIMENSION_TABLE, member.getId() + ":" + member.getGuild().getId()) == 1; + } catch (SQLException e) { + e.printStackTrace(); + } + return false; + } + public boolean isEnchanted(Member member) { long fortune = getFortune(member); return fortune > 0; @@ -85,7 +184,7 @@ class Pickaxes { return pickaxeLevelToName(level); } - private static String pickaxeLevelToName(long level) { + public static String pickaxeLevelToName(long level) { switch ((int) level) { case 0: return "Stone"; @@ -144,11 +243,20 @@ class Pickaxes { return (int) getFortune(member); } + public int getPickaxeEfficiency(Member member) { + return (int) getEfficiency(member); + } + public int incrementFortune(Member member) { setFortune(member, getFortune(member) + 1); return (int) getFortune(member); } + public int incrementEfficiency(Member member) { + setEfficiency(member, getEfficiency(member) + 1); + return (int) getEfficiency(member); + } + public static String getRomanNumber(int number) { return String.join("", Collections.nCopies(number, "I")) .replace("IIIII", "V") diff --git a/src/main/java/net/uomc/mineshaft/RobCommand.java b/src/main/java/net/uomc/mineshaft/RobCommand.java index c04f2f4..9ff8a12 100644 --- a/src/main/java/net/uomc/mineshaft/RobCommand.java +++ b/src/main/java/net/uomc/mineshaft/RobCommand.java @@ -28,7 +28,7 @@ import net.dv8tion.jda.api.events.message.MessageReceivedEvent; public class RobCommand extends CooldownCommand { private static final int TO_PICK = 3; - private static final double MAX_AMOUNT_PERCENT = 0.2; + private static final double MAX_AMOUNT_PERCENT = 0.35; private static final long DROP_DURATION_SECONDS = 90; private static final String LOOT_STRING = "loot"; private Mineshaft bot; @@ -57,6 +57,11 @@ public class RobCommand extends CooldownCommand { } Member target = mentionToMember.get(); + if (bot.getPickaxes().isNether(target) != bot.getPickaxes().isNether(e.getMember())) { + e.getMessage().reply(":x: You tried to kill " + target.getAsMention() + " but they were in a different dimension!").queue(); + return false; + } + String response = target.getAsMention() + " was slain by " + e.getAuthor().getAsMention(); Map rob = getRob(target); diff --git a/src/main/java/net/uomc/mineshaft/crafting/Crafting.java b/src/main/java/net/uomc/mineshaft/crafting/Crafting.java index 5bbef1c..6e2f670 100644 --- a/src/main/java/net/uomc/mineshaft/crafting/Crafting.java +++ b/src/main/java/net/uomc/mineshaft/crafting/Crafting.java @@ -19,6 +19,7 @@ import net.uomc.mineshaft.resources.Resource; import net.uomc.mineshaft.Mineshaft; import net.uomc.mineshaft.MineshaftItem; import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; @@ -45,6 +46,7 @@ public class Crafting extends DetailedCommand { addRecipe( CraftingRecipe.make(MineshaftItem.BOOKSHELF) .addIngredient(MineshaftItem.BOOK, 3) + .setUnlockCondition((m) -> bot.getItem(m, MineshaftItem.BOOK) > 0) .setBuyMessage("**+1 enchanting table level**") ); @@ -53,6 +55,56 @@ public class Crafting extends DetailedCommand { .addIngredient(MineshaftItem.COAL, 800l) .setBuyMessage("Use `" + bot.getCommandController().getPrefix() + "furnace` to get free ores") ); + + addRecipe( + CraftingRecipe.make(MineshaftItem.PORTAL) + .addIngredient(MineshaftItem.OBSIDIAN, 10l) + .setUnlockCondition((m) -> bot.getItem(m, MineshaftItem.OBSIDIAN) > 0) + .setBuyMessage("You can now use your `" + bot.getCommandController().getPrefix() + "portal`") + ); + + addRecipe( + CraftingRecipe.make(MineshaftItem.WOOL) + .addIngredient(MineshaftItem.STRING, 4l) + .setUnlockCondition((m) -> bot.getItem(m, MineshaftItem.STRING) > 0) + ); + + addRecipe( + CraftingRecipe.make(MineshaftItem.BED) + .addIngredient(MineshaftItem.WOOL, 3l) + .setUnlockCondition((m) -> bot.getItem(m, MineshaftItem.STRING) > 0) + ); + + addRecipe( + CraftingRecipe.make(MineshaftItem.VILLAGER) + .addIngredient(MineshaftItem.EMERALD, 64l) + .addIngredient(MineshaftItem.BED, 1l) + .setUnlockCondition((m) -> bot.getItem(m, MineshaftItem.BED) > 0 && bot.getItem(m, MineshaftItem.EMERALD) > 0) + .setBuyMessage("You are now able to `" + bot.getCommandController().getPrefix() + "trade` with the wandering trader") + ); + + addRecipe( + CraftingRecipe.make(MineshaftItem.COMPOSTER) + .addIngredient(MineshaftItem.IRON, 14l) + .setUnlockCondition((m) -> + bot.getItem(m, MineshaftItem.FISH) > 0 + || bot.getItem(m, MineshaftItem.POTATO) > 0 + || bot.getItem(m, MineshaftItem.CARROT) > 0 + || bot.getItem(m, MineshaftItem.CANE) > 0) + .setBuyMessage("You are now able to `" + bot.getCommandController().getPrefix() + "compost` your items") + ); + + addRecipe( + CraftingRecipe.make(MineshaftItem.PAPER) + .addIngredient(MineshaftItem.CANE, 3l) + .setUnlockCondition((m) -> bot.getItem(m, MineshaftItem.CANE) > 0) + ); + + addRecipe( + CraftingRecipe.make(MineshaftItem.BOOK) + .addIngredient(MineshaftItem.PAPER, 27l) + .setUnlockCondition((m) -> bot.getItem(m, MineshaftItem.PAPER) > 0) + ); } @@ -72,9 +124,9 @@ public class Crafting extends DetailedCommand { return; } - String description = "This is your crafting table. Craft an item with `" + b.getPrefixManager().getPrefix(e.getGuild()) + "craft [item]`\n\n"; + String description = "This is your crafting table. Craft an item with `" + b.getPrefixManager().getPrefix(e.getGuild()) + "craft [item] [amount]`\n\n"; - description += getCraftingRecipesList(); + description += getCraftingRecipesList(e.getMember()); EmbedBuilder em = new EmbedBuilder(); em.setTitle(COMMAND_TITLE); @@ -82,13 +134,19 @@ public class Crafting extends DetailedCommand { em.setThumbnail(COMMAND_IMAGE); em.setColor(PeelingUtils.hex2Rgb("#93764c")); - em.setFooter(EmojiParser.parseToUnicode(":bulb:") + "View your inventory with " +b.getPrefixManager().getPrefix(e.getGuild()) + "inv"); + if (bot.getItem(e.getMember(), MineshaftItem.DIAMOND) < 1) { + em.setFooter(EmojiParser.parseToUnicode(":bulb:") + "View your inventory with " +b.getPrefixManager().getPrefix(e.getGuild()) + "inv"); + } else { + em.setFooter(EmojiParser.parseToUnicode(":bulb:") + "Come back once you have more items to unlock more recipes!"); + } e.getMessage().replyEmbeds(em.build()).queue(); } - public String getCraftingRecipesList() { - return getRecipes().stream().map(recipe -> { + public String getCraftingRecipesList(Member member) { + return getRecipes().stream() + .filter(r -> r.isUnlocked(member)) + .map(recipe -> { Resource r = bot.getItem(recipe.getItem()); return "**" + r.getPrettyName() + "**\n" diff --git a/src/main/java/net/uomc/mineshaft/crafting/CraftingRecipe.java b/src/main/java/net/uomc/mineshaft/crafting/CraftingRecipe.java index cb4892e..5f624a0 100644 --- a/src/main/java/net/uomc/mineshaft/crafting/CraftingRecipe.java +++ b/src/main/java/net/uomc/mineshaft/crafting/CraftingRecipe.java @@ -3,6 +3,11 @@ package net.uomc.mineshaft.crafting; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.function.BiFunction; +import java.util.function.Function; + +import net.dv8tion.jda.api.entities.Member; +import net.uomc.mineshaft.Mineshaft; import net.uomc.mineshaft.MineshaftItem; public class CraftingRecipe { @@ -11,6 +16,7 @@ public class CraftingRecipe { Map ingredients; String buyMessage; + Function unlockCondition; private CraftingRecipe(MineshaftItem item, long quantity, Map ingredients) { this.item = item; @@ -41,13 +47,28 @@ public class CraftingRecipe { } public String getBuyMessage() { + if (buyMessage == null) + return ""; return buyMessage; } + public boolean isUnlocked(Member m) { + if (unlockCondition == null) + return true; + + return unlockCondition.apply(m); + } + public CraftingRecipe setBuyMessage(String message) { buyMessage = message; return this; } + + public CraftingRecipe setUnlockCondition(Function function) { + this.unlockCondition = function; + return this; + } + public Map getMissingIngredients(Map items) { return getMissingIngredients(items, 1); } diff --git a/src/main/java/net/uomc/mineshaft/resources/Resource.java b/src/main/java/net/uomc/mineshaft/resources/Resource.java index 1cd508e..3b02050 100644 --- a/src/main/java/net/uomc/mineshaft/resources/Resource.java +++ b/src/main/java/net/uomc/mineshaft/resources/Resource.java @@ -123,7 +123,7 @@ public class Resource extends JSONObject { } public long getValue() { - if (total() <= 0) { + if (total() <= 0 || resourceManager.getPrimaryResource().total() <= 0) { return -1; } else { return resourceManager.getPrimaryResource().total() / total(); diff --git a/src/main/java/net/uomc/mineshaft/resources/ResourceManager.java b/src/main/java/net/uomc/mineshaft/resources/ResourceManager.java index 8c58ab3..da1bd83 100644 --- a/src/main/java/net/uomc/mineshaft/resources/ResourceManager.java +++ b/src/main/java/net/uomc/mineshaft/resources/ResourceManager.java @@ -45,6 +45,7 @@ public class ResourceManager { private MarketManager marketManager; + public ResourceManager(CustomBot customBot) { this.bot = customBot; configFile = new File(customBot.getDatadir(), "resources_config.json"); @@ -168,6 +169,10 @@ public class ResourceManager { Resource resource = getResource(primaryResource); return resource == null ? resources.get(0) : resource; + } + public long getTotalResources() { + return resources.stream().mapToLong(r -> r.total()).sum(); + } public String getPrimaryResourceName() { @@ -221,4 +226,8 @@ public class ResourceManager { }); return string.toString(); } + + public MarketManager getMarketManager() { + return marketManager; + } } diff --git a/src/main/java/net/uomc/mineshaft/resources/commands/GiveResourcesCommand.java b/src/main/java/net/uomc/mineshaft/resources/commands/GiveResourcesCommand.java index a98a452..2925bd4 100644 --- a/src/main/java/net/uomc/mineshaft/resources/commands/GiveResourcesCommand.java +++ b/src/main/java/net/uomc/mineshaft/resources/commands/GiveResourcesCommand.java @@ -2,6 +2,8 @@ package net.uomc.mineshaft.resources.commands; import static java.lang.Math.abs; +import java.util.List; +import java.util.Arrays; import java.util.Optional; import com.mouldycheerio.dbot.CustomBot; @@ -9,7 +11,6 @@ import com.mouldycheerio.dbot.commands.CommandDetails; import com.mouldycheerio.dbot.util.PeelingUtils; import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.uomc.mineshaft.resources.Resource; import net.uomc.mineshaft.resources.ResourceManager; @@ -20,66 +21,73 @@ public class GiveResourcesCommand extends ResourceCommand { public GiveResourcesCommand(ResourceManager resourceManager) { super(resourceManager); - setCommandDetails(CommandDetails.from("give,trade", "Give a user an item", "give [@user] [quantity] [item]")); + setCommandDetails(CommandDetails.from("give", "Give a user an item", "give [@user] [quantity] [item]")); usage = "\n`" + getCommandDetails().getUsage() + "`"; } @Override public void execute(MessageReceivedEvent e, CustomBot op, String[] args) { - if (args.length > 1) { - String usermention = args[0]; - String quantitystring = args[1]; - String resourcename = getResourceManager().getPrimaryResourceName(); - if (args.length > 2) { - resourcename = args[2]; - } - - boolean generate = false; - String ownerid = op.getConfig().getString("ownerid"); - if (ownerid.equals(e.getAuthor().getId())) { - if (args.length > 3) { - if (args[3].equals("generate")) { - generate = true; - } - } - } - Optional mentionToUser = PeelingUtils.mentionToMember(usermention, e.getGuild()); - if (mentionToUser.isPresent()) { - Member member = mentionToUser.get(); - try { - long quantity = Long.parseLong(quantitystring); - quantity = abs(quantity); - - Resource resource = getResourceManager().getResource(resourcename); - if (resource != null) { - - if (!generate && quantity > resource.get(e.getMember())) { - op.sendErrorMessage(e,":x: You do not have enough " + resource.getName() + "!"); - } else { - if (!generate) { - resource.increment(e.getMember(), -quantity); - } - resource.increment(member, quantity); - op.sendSuccessMessage(e, ":white_check_mark: You gave " + member.getAsMention() + " " + resource.prettyValue(quantity)); - } - } else { - op.sendErrorMessage(e, ":x: Please provide a valid resource!" + usage); - - } - - } catch (NumberFormatException ex) { - op.sendErrorMessage(e,":x: Please provide a valid quantity!" + usage); - - } - - } else { - op.sendErrorMessage(e, ":x: That user was not found!" + usage); - } - } else { + if (args.length < 3) { op.sendErrorMessage(e, ":x: Invalid usage!" + usage); + return; + } + List argList = Arrays.asList(args); + + Optional memberMention = argList.stream().filter(s -> s.startsWith("<@")).findFirst(); + + if (memberMention.isEmpty()) { + op.sendErrorMessage(e, ":x: Invalid usage!" + usage); + return; + } + + Optional quantity = argList.stream().filter(s -> PeelingUtils.isLong(s)).map(s -> Long.parseLong(s)) + .findFirst(); + if (quantity.isEmpty()) { + op.sendErrorMessage(e, ":x: Invalid usage!" + usage); + return; + } + Optional resourceName = argList.stream().filter(s -> !s.startsWith("<@") && !PeelingUtils.isLong(s)) + .findFirst(); + if (resourceName.isEmpty()) { + op.sendErrorMessage(e, ":x: Invalid usage!" + usage); + return; + } + + boolean generate = argList.stream().filter(s -> "generate".equals(s)).findFirst().isPresent(); + if (!e.getMember().getId().equals(op.getOwnerID())){ + generate = false; } + + Optional mentionToUser = PeelingUtils.mentionToMember(memberMention.get(), e.getGuild()); + + if (!mentionToUser.isPresent()) { + op.sendErrorMessage(e, ":x: That user was not found!" + usage); + return; + } + + Member member = mentionToUser.get(); + long q = abs(quantity.get()); + + Resource resource = getResourceManager().getResource(resourceName.get()); + if (resource == null) { + op.sendErrorMessage(e, ":x: Please provide a valid resource!" + usage); + return; + } + + if (!generate && q > resource.get(e.getMember())) { + op.sendErrorMessage(e, ":x: You do not have enough " + resource.getName() + "!"); + return; + } + + if (!generate) { + resource.increment(e.getMember(), -q); + } + + resource.increment(member, q); + op.sendSuccessMessage(e, + ":white_check_mark: You gave " + member.getAsMention() + " " + resource.prettyValue(q)); } } diff --git a/src/main/java/net/uomc/mineshaft/resources/commands/ValuesCommand.java b/src/main/java/net/uomc/mineshaft/resources/commands/ValuesCommand.java index c094d83..084856b 100644 --- a/src/main/java/net/uomc/mineshaft/resources/commands/ValuesCommand.java +++ b/src/main/java/net/uomc/mineshaft/resources/commands/ValuesCommand.java @@ -7,6 +7,7 @@ import java.util.List; import com.mouldycheerio.dbot.CustomBot; import com.mouldycheerio.dbot.commands.CommandDetails; import com.mouldycheerio.dbot.commands.CommandFail; +import com.mouldycheerio.dbot.util.PeelingUtils; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.uomc.mineshaft.resources.Resource; @@ -21,8 +22,6 @@ public class ValuesCommand extends ResourceCommand { @Override public void execute(MessageReceivedEvent e, CustomBot b, String[] args) throws CommandFail { - long total = getResourceManager().getPrimaryResource().total(); - List resources = new ArrayList(getResourceManager().getResources()); Collections.sort(resources, (r1, r2) -> Long.compare(r2.getValue(),r1.getValue())); @@ -33,13 +32,11 @@ public class ValuesCommand extends ResourceCommand { if (v < 0) { stringBuilder.append("**???**"); } else { - stringBuilder.append("**" + getResourceManager().getPrimaryResource().prettyValue(v) + "**"); + stringBuilder.append("**" +PeelingUtils.amountToString(v) + "**"); } stringBuilder.append("\n"); }); b.sendMessage(e, "Estimated Market Values", stringBuilder.toString()); } - - } diff --git a/src/main/java/net/uomc/mineshaft/resources/market/MarketCommand.java b/src/main/java/net/uomc/mineshaft/resources/market/MarketCommand.java index 47b0536..7b4122a 100644 --- a/src/main/java/net/uomc/mineshaft/resources/market/MarketCommand.java +++ b/src/main/java/net/uomc/mineshaft/resources/market/MarketCommand.java @@ -6,12 +6,14 @@ import com.mouldycheerio.dbot.CustomBot; import com.mouldycheerio.dbot.commands.CommandDetails; import com.mouldycheerio.dbot.commands.DetailedCommand; import com.mouldycheerio.dbot.util.PeelingUtils; +import com.vdurmont.emoji.EmojiParser; import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.MessageEmbed.Field; +import net.dv8tion.jda.api.entities.emoji.Emoji; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.uomc.mineshaft.resources.Resource; import net.uomc.mineshaft.resources.ResourceManager; -import net.uomc.mineshaft.resources.market.Offer; public class MarketCommand extends DetailedCommand { private ResourceManager resourceManager; @@ -26,21 +28,30 @@ public class MarketCommand extends DetailedCommand { @Override public void execute(MessageReceivedEvent e, CustomBot op, String[] args) { + market(e, op, args); + } - marketManager.processOffers(); + private void market(MessageReceivedEvent e, CustomBot op, String[] args) { + marketManager.processOffers(e.getGuild()); if (args.length == 0) { - // TODO allow multipages with <-, -> - EmbedBuilder embedBuilder = new EmbedBuilder(); embedBuilder.setTitle("Market"); embedBuilder.setColor(op.color); - if (marketManager.getEmbedFields().size() == 0) { + List embedFields = marketManager.getEmbedFields(e.getGuild()); + if (embedFields.size() == 0) { embedBuilder.setDescription("**:x: There are no available offers!**\n" + "Create one with `market sell`"); e.getMessage().replyEmbeds(embedBuilder.build()).queue(); } else { - embedBuilder.setDescription("Use `" + op.getPrefixManager().getPrefix(e.getGuild()) + "market buy [id]` to accept an offer"); - PeelingUtils.pagesEmbed(e.getAuthor(), e.getChannel(), embedBuilder, marketManager.getEmbedFields()); - } + embedBuilder.setDescription( + "Use `" + op.getPrefixManager().getPrefix(e.getGuild()) + "market buy [id]` to accept an offer\n" ++ "Use `" + op.getPrefixManager().getPrefix(e.getGuild()) + "market sell` to create an offer\n" + ); + + e.getMessage().addReaction(Emoji.fromUnicode(EmojiParser.parseToUnicode(":white_check_mark:"))) + .queue((r) -> { + PeelingUtils.pagesEmbed(e.getAuthor(), e.getChannel(), embedBuilder, embedFields); + }); + } } else if (args.length > 0) { if (args[0].equals("buy")) { @@ -76,7 +87,7 @@ public class MarketCommand extends DetailedCommand { offer.setSellingQuantity(sellQ); offer.setSellingResource(sellR); - marketManager.addOffer(offer); + marketManager.addOffer(e.getGuild(), offer); op.sendSuccessMessage(e, ":white_check_mark: successfully listed **" + offer.getAsString(resourceManager) + "** offer id: `" + offer.getID() + "`"); } else { op.sendErrorMessage(e, ":x: You don't have enough " + sellR + " to offer"); @@ -99,19 +110,20 @@ public class MarketCommand extends DetailedCommand { int q1 = (int) (Math.random() * 10); int q2 = (int) (Math.random() * 10); - op.sendMessage( - e, "incorrect usage", + op.sendErrorMessage( + e, ":x: usage: `market sell [items] for [price]`\ni.e: `market sell " + q1 + " " + resource1.getName() + " for " + q2 + " " + resource2.getName() + "`" ); } private void buy(MessageReceivedEvent e, CustomBot op, String[] args) { String id = args[1]; - Offer offer = marketManager.getOffer(id); + Offer offer = marketManager.getOffer(e.getGuild(), id); if (offer != null) { offer.getMember(e.getGuild(), seller -> { - if (seller.equals(e.getAuthor())) { - op.sendErrorMessage(e, ":x: you cannot accept your own offer"); + + if (e.getMember().equals(seller)) { + op.sendErrorMessage(e, ":x: You cannot accept your own offer"); } else { long buyingQuantity = offer.getBuyingQuantity(); Resource buyingResource = offer.getBuyingResource(resourceManager); @@ -120,6 +132,12 @@ public class MarketCommand extends DetailedCommand { long sellingQuantity = offer.getSellingQuantity(); Resource sellingResource = offer.getSellingResource(resourceManager); + if (sellingResource.get(seller) < sellingQuantity) { + op.sendErrorMessage(e, ":x: This offer no longer exists as " + seller.getAsMention() + "does not have enough " + sellingResource.getName()); + marketManager.removeOffer(e.getGuild(), offer); + return; + } + buyingResource.increment(e.getMember(), -buyingQuantity); sellingResource.increment(e.getMember(), sellingQuantity); @@ -127,6 +145,7 @@ public class MarketCommand extends DetailedCommand { buyingResource.increment(seller, buyingQuantity); sellingResource.increment(seller, -sellingQuantity); } + seller.getUser().openPrivateChannel().queue(pc -> { pc.sendMessage( "**" + e.getAuthor().getAsTag() + "** has accepted your market offer: **" + offer.getAsString(resourceManager) + "** [" + offer.getID() + "]" @@ -134,26 +153,25 @@ public class MarketCommand extends DetailedCommand { .queue(); }); - String from = ""; - if (seller != null) { - from = " from " + seller.getAsMention(); - } + String from = " from " + seller.getAsMention(); - marketManager.removeOffer(offer); - op.sendSuccessMessage( + marketManager.removeOffer(e.getGuild(), offer); + e.getMessage().addReaction(Emoji.fromUnicode(EmojiParser.parseToUnicode(":white_check_mark:"))).queue((r) -> { + op.sendMessageRaw( e, ":white_check_mark: successfully bought **" + sellingResource.prettyValue(sellingQuantity) + "** for **" + buyingResource.prettyValue(buyingQuantity) + "**" + from ); + }); } else { long have = buyingResource.get(e.getMember()); long more = buyingQuantity - have; - op.sendErrorMessage(e, ":x: you need **" + buyingResource.prettyValue(more) + "** more to buy this"); + op.sendErrorMessage(e, ":x: You need **" + buyingResource.prettyValue(more) + "** more to buy this"); } } }); } else { - op.sendErrorMessage(e, ":x: please specify a valid id!"); + op.sendErrorMessage(e, ":x: Please specify a valid id!"); } } } diff --git a/src/main/java/net/uomc/mineshaft/resources/market/MarketManager.java b/src/main/java/net/uomc/mineshaft/resources/market/MarketManager.java index 05517aa..3b820b5 100644 --- a/src/main/java/net/uomc/mineshaft/resources/market/MarketManager.java +++ b/src/main/java/net/uomc/mineshaft/resources/market/MarketManager.java @@ -3,8 +3,10 @@ package net.uomc.mineshaft.resources.market; import java.io.File; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import org.json.JSONObject; @@ -12,6 +14,7 @@ import org.json.JSONObject; import com.mouldycheerio.dbot.CustomBot; import com.mouldycheerio.dbot.util.PeelingUtils; +import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.MessageEmbed.Field; import net.dv8tion.jda.api.entities.User; import net.uomc.mineshaft.resources.Resource; @@ -21,7 +24,7 @@ import net.uomc.mineshaft.resources.market.Offer; public class MarketManager { private ResourceManager resourceManager; - private List offers = new ArrayList(); + private Map> guildOffers = new HashMap>(); private File dataFile; @@ -38,27 +41,48 @@ public class MarketManager { public void load() { JSONObject loadJSON = PeelingUtils.loadJSON(dataFile); - if (loadJSON.has("offers")) { - loadJSON.getJSONArray("offers").forEach(o -> { - if (o instanceof JSONObject) { - Offer offer = new Offer((JSONObject) o); - offers.add(offer); - } + if (loadJSON.has("guilds")) { + loadJSON.getJSONObject("guilds").keySet().forEach(g -> { + Guild guild = bot.getClient().getGuildById(g); + if (guild == null) + return; + + guildOffers.put(guild, new ArrayList()); + + loadJSON.getJSONObject("guilds").getJSONArray(g).forEach(o -> { + if (o instanceof JSONObject) { + Offer offer = new Offer((JSONObject) o); + guildOffers.get(guild).add(offer); + } + }); }); } } public void save() { JSONObject jsonObject = new JSONObject(); - for (Offer offer : offers) { - jsonObject.append("offers", offer); - } + + JSONObject guilds = new JSONObject(); + + guildOffers.forEach((g, l) -> { + l.forEach(o -> { + guilds.append(g.getId(), o); + }); + }); + jsonObject.put("guilds", guilds); PeelingUtils.saveJSON(dataFile, jsonObject); } - public Offer getOffer(String id) { - for (Offer offer : offers) { + public List getOffers(Guild guild) { + if (!guildOffers.containsKey(guild)) { + guildOffers.put(guild, new ArrayList()); + } + return guildOffers.get(guild); + } + + public Offer getOffer(Guild guild, String id) { + for (Offer offer : getOffers(guild)) { if (id.equals(offer.getID() + "")) { return offer; } @@ -66,27 +90,23 @@ public class MarketManager { return null; } - public void addOffer(Offer offer) { - offers.add(offer); - processOffers(); + public void addOffer(Guild guild, Offer offer) { + getOffers(guild).add(offer); + processOffers(guild); + save(); } - public void processOffers() { - // TODO uhhh we should bring this back - //Iterator iterator = offers.iterator(); + public void processOffers(Guild guild) { + // TODO Fix tis + //Iterator iterator = getOffers(guild).iterator(); //while (iterator.hasNext()) { // Offer offer = iterator.next(); - // bot.getClient().retrieveUserById(offer.getUserID()).queue(seller -> { - // long quantity = offer.getSellingQuantity(); - // Resource resource = offer.getSellingResource(resourceManager); - // long l = resource.get(seller); - // if (l < quantity) { + // if (l < quantity) { - // sendNoLongerValidMessage(offer, seller); - // iterator.remove(); - // } - // }); + // sendNoLongerValidMessage(offer, seller); + // iterator.remove(); + // } //} //save(); @@ -98,17 +118,17 @@ public class MarketManager { }); } - public void removeOffer(Offer o) { - offers.remove(o); + public void removeOffer(Guild guild, Offer o) { + getOffers(guild).remove(o); save(); } - public List listOffers() { - return Collections.unmodifiableList(offers); + public List listOffers(Guild guild) { + return Collections.unmodifiableList(getOffers(guild)); } - public List getEmbedFields() { - return listOffers().stream().map( + public List getEmbedFields(Guild guild) { + return listOffers(guild).stream().map( o -> new Field( "[" + o.getID() + "] " + o.getAsString(resourceManager), diff --git a/src/main/java/net/uomc/mineshaft/resources/market/Offer.java b/src/main/java/net/uomc/mineshaft/resources/market/Offer.java index 9e01acd..d093f2f 100644 --- a/src/main/java/net/uomc/mineshaft/resources/market/Offer.java +++ b/src/main/java/net/uomc/mineshaft/resources/market/Offer.java @@ -53,7 +53,7 @@ public class Offer extends JSONObject { } public void getMember(Guild guild, Consumer c) { - c.accept(guild.getMemberById(getUserID())); + guild.retrieveMemberById(getUserID()).queue(c); } public Member getMember(Guild guild) { -- cgit v1.2.3