package net.uomc.mineshaft.farm; import java.awt.Color; import java.util.ArrayList; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import com.mouldycheerio.dbot.commands.CommandDetails; import com.mouldycheerio.dbot.commands.cooldowns.CooldownCommand; import com.mouldycheerio.dbot.util.EventWaiter; import com.mouldycheerio.dbot.util.PeelingUtils; import com.vdurmont.emoji.EmojiParser; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; import net.dv8tion.jda.api.entities.emoji.Emoji; import net.dv8tion.jda.api.entities.emoji.UnicodeEmoji; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.events.message.react.MessageReactionAddEvent; import net.uomc.mineshaft.Mineshaft; import net.uomc.mineshaft.MineshaftItem; import net.uomc.mineshaft.resources.Resource; public class TradeCommand extends CooldownCommand { private static final UnicodeEmoji EXCLAIM = Emoji.fromUnicode(EmojiParser.parseToUnicode(":grey_exclamation:")); private static final UnicodeEmoji YES = Emoji.fromUnicode(EmojiParser.parseToUnicode(":white_check_mark:")); private static final UnicodeEmoji NO = Emoji.fromUnicode(EmojiParser.parseToUnicode(":x:")); private static final Color COMMAND_COLOR = PeelingUtils.hex2Rgb("#375482"); private static final String COMMAND_IMAGE = "https://minecraft.wiki/images/thumb/Wandering_Trader_JE1_BE1.png/270px-Wandering_Trader_JE1_BE1.png?62e9e"; private static final String COMMAND_TITLE = "A wandering trader has spawned"; private static final String ACCEPT_STRING = "accept"; private static final double VALUE_MULTIPLIER = 1.1; private static final double NEW_ITEM_ITEM_VALUE = 0.3; private static final long TRADE_DURATION_SECONDS = 90; private static final double MAX_AMOUNT_PERCENT = 0.2; public static MineshaftItem[] traderItems = { MineshaftItem.CARROT, MineshaftItem.CANE, MineshaftItem.POTATO, MineshaftItem.BOOK, MineshaftItem.LAPIS, MineshaftItem.COAL, MineshaftItem.WOOL, }; public static MineshaftItem[] buyingItems = { MineshaftItem.CARROT, MineshaftItem.CANE, MineshaftItem.POTATO, }; Mineshaft bot; public TradeCommand(Mineshaft bot) { super(bot); setCommandDetails(CommandDetails.from("trade,trader,wanderingtrader", "trade with the wandering trader", "trade")); this.bot = bot; setCooldown(90l * 60l * 1000l); } @Override public boolean trigger(MessageReceivedEvent e) { long villagers = bot.getItem(e.getMember(), MineshaftItem.VILLAGER); if (villagers < 1) { bot.sendErrorMessage(e, ":x: You need to have at least **" + bot.getItem(MineshaftItem.VILLAGER).prettyValue(1) + "** to use this!"); return false; } String description = "The trader has a deal for you:\n\n"; MineshaftItem trade = newTrade(); boolean inverse = isInverseTrade(e.getMember(), trade); MineshaftItem giveItem; MineshaftItem getItem; if (inverse) { giveItem = trade; getItem = MineshaftItem.EMERALD; } else { getItem = trade; giveItem = MineshaftItem.EMERALD; } long q = getTradeQuantity(e.getMember(), getItem); long p = getPrice(giveItem, getItem, q); long userGive = bot.getItem(e.getMember(), giveItem); long userGet = bot.getItem(e.getMember(), getItem); description += String.format("**%s**🡒**%s**", bot.getItem(giveItem).prettyValue(p), bot.getItem(getItem).prettyValue(q)); description += String.format( "\n\n:warning:Warning this offer expires in %s and you will need to wait `%s` before trading again", PeelingUtils.formatTimeRelativeFromNow(TRADE_DURATION_SECONDS * 1000l), PeelingUtils.formatTime(getCooldown(), false) ); description += String.format("\n\nYou have **%s**", bot.getItem(giveItem).prettyValue(userGive)); if (userGet > 0) { description += String.format(", **%s**", bot.getItem(getItem).prettyValue(userGet)); } EmbedBuilder em = new EmbedBuilder(); em.setTitle(COMMAND_TITLE); em.setDescription(description); em.setThumbnail(COMMAND_IMAGE); em.setColor(COMMAND_COLOR); e.getMessage().replyEmbeds(em.build()).queue(m -> { m.addReaction(YES).queue(m1 -> { m.addReaction(NO).queue(m2 -> { EventWaiter eventWaiter = new EventWaiter(); e.getMessage().getJDA().addEventListener(eventWaiter); eventWaiter.waitForEvent(MessageReactionAddEvent.class, e1 -> { if (!e1.getMessageId().equals(m.getId())) return false; if (!e1.getMember().getId().equals(e.getMember().getId())) return false; if (e1.getEmoji().asUnicode().getFormatted().equals(YES.getFormatted())) return true; if (e1.getEmoji().asUnicode().getFormatted().equals(NO.getFormatted())) return true; return false; }, e1 -> { if (e1.getEmoji().asUnicode().getFormatted().equals(YES.getFormatted())) { acceptTrade(e.getMember(), giveItem, getItem, q, p, m); } else { m.delete().queue(); } }, TRADE_DURATION_SECONDS, TimeUnit.SECONDS, () -> { m.delete().queue(); }); }); }); }); e.getMessage().addReaction(EXCLAIM).queue(); return true; } private void acceptTrade(Member member, MineshaftItem giveItem, MineshaftItem getItem, long quantity, long price, Message message) { String description = ""; long userGive = bot.getItem(member, giveItem); if (userGive >= price) { bot.removeItem(member, giveItem, price); bot.addItem(member, getItem, quantity); description = String.format("You accepted the trade! +**%s**, -**%s**", bot.getItem(getItem).prettyValue(quantity), bot.getItem(giveItem).prettyValue(price)); } else { description = String.format("You don't have enough! You have **%s**", bot.getItem(giveItem).prettyValue(userGive)); } description += "\nThe trader leaves, for now..."; EmbedBuilder em = new EmbedBuilder(); em.setTitle(COMMAND_TITLE); em.setDescription(description); em.setThumbnail(COMMAND_IMAGE); em.setColor(COMMAND_COLOR); message.clearReactions().queue(m -> { message.editMessageEmbeds(em.build()).queue(m2 -> { //m2.delete().queueAfter(10, TimeUnit.SECONDS); }); }); } public void cleanup(MessageChannel channel, Message message) { message.delete().queue(a -> {}, x -> {}); channel.getHistoryAfter(message, 100).queueAfter(5, TimeUnit.SECONDS, h -> { ArrayList msgs = new ArrayList(); h.getRetrievedHistory().forEach(m -> { if (m.getContentRaw().equalsIgnoreCase(ACCEPT_STRING)) { msgs.add(m); } }); PeelingUtils.bulkDelte(channel, msgs); }); ; } public MineshaftItem newTrade() { return traderItems[(int) (traderItems.length * Math.random())]; } public long getTradeQuantity(Member m, MineshaftItem item) { return (long) ((Math.random() * MAX_AMOUNT_PERCENT * bot.getItem(m, item)) + 1); } public long getPrice(MineshaftItem giveItem, MineshaftItem getItem, long quantity) { long giveValue = bot.getItem(giveItem).getValue(); if (giveValue <= 0) { giveValue = (long) (bot.getResourceManager().getTotalResources() * NEW_ITEM_ITEM_VALUE * Math.random()); } long getValue = bot.getItem(getItem).getValue(); if (getValue <= 0) { getValue = (long) (bot.getResourceManager().getTotalResources() * NEW_ITEM_ITEM_VALUE * Math.random()); } return (long) (quantity * getValue * VALUE_MULTIPLIER / giveValue) + 1; } public boolean isInverseTrade(Member member, MineshaftItem item) { boolean isBuying = false; for (int i = 0; i < buyingItems.length; i++) { if (buyingItems[i] == item) { isBuying = true; break; } } if (isBuying) return bot.getItem(member, item) > 0; return false; } }