summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pom.xml6
-rw-r--r--src/main/java/net/uomc/mineshaft/EatCommand.java134
-rw-r--r--src/main/java/net/uomc/mineshaft/EnchantCommand.java54
-rw-r--r--src/main/java/net/uomc/mineshaft/FishCommand.java4
-rw-r--r--src/main/java/net/uomc/mineshaft/MineCommand.java20
-rw-r--r--src/main/java/net/uomc/mineshaft/Mineshaft.java62
-rw-r--r--src/main/java/net/uomc/mineshaft/MineshaftGiveResourcesCommand.java2
-rw-r--r--src/main/java/net/uomc/mineshaft/MineshaftItem.java5
-rw-r--r--src/main/java/net/uomc/mineshaft/MineshaftLeaderBoardCommand.java21
-rw-r--r--src/main/java/net/uomc/mineshaft/PickaxeCommand.java30
-rw-r--r--src/main/java/net/uomc/mineshaft/Pickaxes.java276
-rw-r--r--src/main/java/net/uomc/mineshaft/PlayerHealths.java131
-rw-r--r--src/main/java/net/uomc/mineshaft/PlayerStats.java80
-rw-r--r--src/main/java/net/uomc/mineshaft/Portal.java6
-rw-r--r--src/main/java/net/uomc/mineshaft/RobCommand.java178
-rw-r--r--src/main/java/net/uomc/mineshaft/SavedStat.java81
-rw-r--r--src/main/java/net/uomc/mineshaft/SleepCommand.java21
-rw-r--r--src/main/java/net/uomc/mineshaft/blacksmith/Armour.java54
-rw-r--r--src/main/java/net/uomc/mineshaft/blacksmith/Blacksmith.java320
-rw-r--r--src/main/java/net/uomc/mineshaft/blacksmith/BlacksmithCommand.java151
-rw-r--r--src/main/java/net/uomc/mineshaft/blacksmith/Map.java0
-rw-r--r--src/main/java/net/uomc/mineshaft/blacksmith/Pickaxe.java211
-rw-r--r--src/main/java/net/uomc/mineshaft/blacksmith/Sword.java77
-rw-r--r--src/main/java/net/uomc/mineshaft/blacksmith/Tool.java33
-rw-r--r--src/main/java/net/uomc/mineshaft/blacksmith/Tools.java48
-rw-r--r--src/main/java/net/uomc/mineshaft/crafting/Crafting.java2
-rw-r--r--src/main/java/net/uomc/mineshaft/farm/Campfire.java24
-rw-r--r--src/main/java/net/uomc/mineshaft/farm/CampfireCommand.java258
-rw-r--r--src/main/java/net/uomc/mineshaft/farm/CompostCommand.java4
-rw-r--r--src/main/java/net/uomc/mineshaft/farm/Farm.java8
-rw-r--r--src/main/java/net/uomc/mineshaft/farm/FarmCommand.java23
-rw-r--r--src/main/java/net/uomc/mineshaft/farm/TradeCommand.java5
32 files changed, 1859 insertions, 470 deletions
diff --git a/pom.xml b/pom.xml
index a8499f8..7a67a91 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,6 +28,12 @@
<artifactId>dbot-logging</artifactId>
<version>0.2.0</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-math3</artifactId>
+ <version>3.6.1</version>
+ </dependency>
+
</dependencies>
<build>
diff --git a/src/main/java/net/uomc/mineshaft/EatCommand.java b/src/main/java/net/uomc/mineshaft/EatCommand.java
new file mode 100644
index 0000000..85a64e7
--- /dev/null
+++ b/src/main/java/net/uomc/mineshaft/EatCommand.java
@@ -0,0 +1,134 @@
+package net.uomc.mineshaft;
+
+import static java.util.Map.entry;
+import java.awt.Color;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+import org.jetbrains.annotations.NotNull;
+
+import com.mouldycheerio.dbot.commands.CommandDetails;
+import com.mouldycheerio.dbot.commands.cooldowns.CooldownCommand;
+import com.mouldycheerio.dbot.commands.cooldowns.CooldownController;
+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.MessageEmbed;
+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.uomc.mineshaft.resources.commands.LeaderBoardCommand;
+
+public class EatCommand extends CooldownCommand {
+
+ private static final UnicodeEmoji EAT_EMOJI = Emoji.fromUnicode(EmojiParser.parseToUnicode(":fork_and_knife:"));
+ private static final Color COMMAND_COLOR = PeelingUtils.hex2Rgb("#b23028");
+ private Mineshaft bot;
+ private Map<MineshaftItem, Long> edible;
+
+ public EatCommand(Mineshaft bot) {
+ super(bot);
+ setCommandDetails(CommandDetails.from("eat", "eat", "eat"));
+ this.bot = bot;
+ setCooldown(60l * 1000l);
+
+ edible = Map.ofEntries(
+ entry(MineshaftItem.POTATO, 1l),
+ entry(MineshaftItem.CARROT, 1l),
+ entry(MineshaftItem.FISH, 2l),
+ entry(MineshaftItem.COOKED_FISH, 10l),
+ entry(MineshaftItem.BAKED_POTATO, 8l)
+ );
+ }
+
+ @Override
+ public boolean trigger(MessageReceivedEvent e) {
+ String[] args = e.getMessage().getContentRaw().split("\\s+");
+ if (args.length > 1) {
+ String arg = String.join("_", Arrays.asList(Arrays.copyOfRange(args, 1, args.length)));
+
+ MineshaftItem item = MineshaftItem.valueOf(arg.toUpperCase());
+ if (item == null) {
+ bot.sendErrorMessage(e, ":x: Please provide a valid item! `m!eat [item]`");
+ return false;
+ }
+
+ return eat(e, item);
+ }
+
+ String edible = getEdibleItems(e.getMember());
+
+ if (edible.length() < 0) {
+ bot.sendErrorMessage(e, ":x: You have no edible items!");
+ return false;
+ }
+
+ EmbedBuilder em = new EmbedBuilder();
+ em.setColor(COMMAND_COLOR);
+ em.setTitle("Eat");
+ em.setDescription("Use `m!eat [item]` to eat an item! The following items can be eaten:\n\n");
+ em.appendDescription(edible);
+
+ e.getMessage().replyEmbeds(em.build()).queue();
+ return false;
+ }
+
+ public Mineshaft getBot() {
+ return bot;
+ }
+
+ public String getEdibleItems(Member m) {
+ return edible.entrySet().stream().filter(entry -> bot.hasItem(m, entry.getKey())).map(entry ->
+ bot.prettyValue(entry.getKey(), 1) + "🡒" + PlayerHealths.getHPString(entry.getValue())
+ ).collect(Collectors.joining("\n"));
+ }
+
+ public boolean eat(MessageReceivedEvent event, MineshaftItem item) {
+ Member member = event.getMember();
+ if (!bot.hasItem(member, item)) {
+ bot.sendErrorMessage(event, "You don't have any " + bot.getItem(item).getSymbol() + " to eat!");
+ return false;
+ }
+
+ if (!isEdible(item)) {
+ bot.sendErrorMessage(event, "This item not edible!");
+ return false;
+ }
+ long hp = bot.getHealths().getHP(member);
+
+ if (hp >= PlayerHealths.MAX_HP) {
+ bot.sendErrorMessage(event, "You can't eat this! You are already at " + PlayerHealths.getHPString(hp));
+ return false;
+ }
+
+ long itemHp = edible.get(item);
+ hp += itemHp;
+ if (hp > PlayerHealths.MAX_HP) {
+ hp = PlayerHealths.MAX_HP;
+ }
+
+ bot.removeItem(member, item, 1);
+ bot.getHealths().setHP(member, hp);
+
+ event.getMessage().addReaction(EAT_EMOJI).queue(r -> {
+ event.getMessage().reply(
+ EAT_EMOJI.getFormatted() + " You ate " + bot.prettyValue(item, 1) +
+ ". You are now on " + bot.getHealths().getHPString(member) + " (+" + itemHp + ")"
+ ).delay(10, TimeUnit.SECONDS)
+ .flatMap(m -> m.delete()).queue();
+ });
+
+ return true;
+ }
+
+ public boolean isEdible(MineshaftItem item) {
+ return edible.entrySet().stream().filter(entry -> entry.getKey() == item).findFirst().isPresent();
+ }
+}
diff --git a/src/main/java/net/uomc/mineshaft/EnchantCommand.java b/src/main/java/net/uomc/mineshaft/EnchantCommand.java
index f147636..293351c 100644
--- a/src/main/java/net/uomc/mineshaft/EnchantCommand.java
+++ b/src/main/java/net/uomc/mineshaft/EnchantCommand.java
@@ -9,7 +9,9 @@ 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.events.message.MessageReceivedEvent;
+import net.uomc.mineshaft.blacksmith.Pickaxe;
public class EnchantCommand extends DetailedCommand {
@@ -41,9 +43,12 @@ public class EnchantCommand extends DetailedCommand {
return;
}
- int fortune = bot.getPickaxes().getPickaxeFortune(e.getMember());
- int efficiency = bot.getPickaxes().getPickaxeEfficiency(e.getMember());
- long bookshelves = bot.getItem(e.getMember(), MineshaftItem.BOOKSHELF);
+ Member m = e.getMember();
+ Pickaxe pick = bot.getPickaxe(m);
+
+ int fortune = pick.getFortune();
+ int efficiency = pick.getEfficiency();
+ long bookshelves = bot.getItem(m, MineshaftItem.BOOKSHELF);
String bookshelfDiscountPercent = "-" + (int) Math.ceil((1 -bookshelfDiscount(bookshelves))*100) + "%";
long xpLevel = getXpLevel(fortune+efficiency, bookshelves);
@@ -52,7 +57,7 @@ public class EnchantCommand extends DetailedCommand {
long xpLevelNormal = getXpLevel(fortune+efficiency, 0);
long lapisLevelNormal = getLapisLevel(fortune+efficiency, 0);
- String curr = "Your pickaxe " + getPickaxeEnchantmentsString(fortune, efficiency);
+ String curr = "Your pickaxe " + pick.getEnchantmentString();
curr += "\n\n";
String description = curr + "Enchant your pickaxe with `" + b.getPrefixManager().getPrefix(e.getGuild()) + "enchant pickaxe`\n\n";
@@ -89,20 +94,6 @@ 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));
}
@@ -121,15 +112,18 @@ public class EnchantCommand extends DetailedCommand {
private void enchant(MessageReceivedEvent e, String[] args) {
- int fortune = bot.getPickaxes().getPickaxeFortune(e.getMember());
- int efficiency = bot.getPickaxes().getPickaxeEfficiency(e.getMember());
+ Member m = e.getMember();
+ Pickaxe pick = bot.getPickaxe(m);
+
+ int fortune = pick.getFortune();
+ int efficiency = pick.getEfficiency();
- long bookshelves = bot.getItem(e.getMember(), MineshaftItem.BOOKSHELF);
+ long bookshelves = bot.getItem(m, MineshaftItem.BOOKSHELF);
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);
+ long memberLapis = bot.getItem(m, MineshaftItem.LAPIS);
+ long memberXp = bot.getItem(m, MineshaftItem.XP);
if (memberLapis < lapisLevel) {
bot.sendErrorMessage(e, ":x: You need " + bot.getItem(MineshaftItem.LAPIS).prettyValue(lapisLevel - memberLapis) + " more lapis!" );
@@ -141,18 +135,18 @@ public class EnchantCommand extends DetailedCommand {
return;
}
- bot.removeItem(e.getMember(), MineshaftItem.LAPIS, lapisLevel);
- bot.removeItem(e.getMember(), MineshaftItem.XP, xpLevel);
+ bot.removeItem(m, MineshaftItem.LAPIS, lapisLevel);
+ bot.removeItem(m, MineshaftItem.XP, xpLevel);
String newEnch = "";
if (Math.random() > 0.5) {
- int level = bot.getPickaxes().incrementFortune(e.getMember());
- newEnch = "**Fortune " + Pickaxes.getRomanNumber(level) + "**";
+ int level = pick.incrementFortune();
+ newEnch = "**Fortune " + Pickaxe.getRomanNumber(level) + "**";
} else {
- int level = bot.getPickaxes().incrementEfficiency(e.getMember());
- newEnch = "**Efficiency " + Pickaxes.getRomanNumber(level) + "**";
-
+ int level = pick.incrementEfficiency();
+ newEnch = "**Efficiency " + Pickaxe.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 37612ca..484e49b 100644
--- a/src/main/java/net/uomc/mineshaft/FishCommand.java
+++ b/src/main/java/net/uomc/mineshaft/FishCommand.java
@@ -37,6 +37,8 @@ public class FishCommand extends CooldownCommand {
private static final String TITLE = "Fishing";
private static final String IMAGE_ROD = "https://minecraft.wiki/images/Fishing_Rod_JE2_BE2.png";
+ private static final String FISHED_STAT = "times_fished";
+
private Mineshaft bot;
protected FishCommand(Mineshaft bot) {
@@ -50,7 +52,7 @@ public class FishCommand extends CooldownCommand {
@Override
public boolean trigger(MessageReceivedEvent e) {
- if (bot.getPickaxes().isNether(e.getMember())) {
+ if (bot.getPlayerStats().isNether(e.getMember())) {
bot.sendErrorMessage(e, ":x: You cannot fish in the nether");
return false;
}
diff --git a/src/main/java/net/uomc/mineshaft/MineCommand.java b/src/main/java/net/uomc/mineshaft/MineCommand.java
index 03207e3..dc9ae6d 100644
--- a/src/main/java/net/uomc/mineshaft/MineCommand.java
+++ b/src/main/java/net/uomc/mineshaft/MineCommand.java
@@ -4,16 +4,13 @@ package net.uomc.mineshaft;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
-import java.util.stream.Collectors;
import org.json.JSONObject;
-import com.mouldycheerio.dbot.CustomBot;
import com.mouldycheerio.dbot.commands.CommandDetails;
import com.mouldycheerio.dbot.commands.cooldowns.CooldownCommand;
import com.mouldycheerio.dbot.util.EventWaiter;
@@ -23,11 +20,9 @@ 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.GuildMessageChannel;
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
import net.dv8tion.jda.api.entities.emoji.Emoji;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
-import net.uomc.mineshaft.resources.ResourceManager;
public class MineCommand extends CooldownCommand {
@@ -50,6 +45,8 @@ public class MineCommand extends CooldownCommand {
private static final double SKULL_SPAWN_AMOUNT = 1;
private static final double NETHERITE_SPAWN_AMOUNT = 1;
+ private static final String MINED_STAT = "times_mined";
+
private Map<String, String> ores;
private List<String> oresList;
private List<String> netherOresList;
@@ -138,7 +135,7 @@ public class MineCommand extends CooldownCommand {
}
public MineshaftItem getOre(Member m, boolean nether) {
- int pickaxe = m == null ? Pickaxes.MAX_PICKAXE_LEVEL : bot.getPickaxes().getPickaxeLevel(m);
+ int pickaxe = m == null ? bot.getPickaxe(m).getMaxLevel() : bot.getPickaxe(m).getLevel();
double random = Math.random();
int maxOre = levelToMaxOre(pickaxe);
@@ -156,7 +153,7 @@ public class MineCommand extends CooldownCommand {
@Override
public boolean trigger(MessageReceivedEvent e) {
- boolean nether = bot.getPickaxes().isNether(e.getMember());
+ boolean nether = bot.getPlayerStats().isNether(e.getMember());
MineshaftItem ore = getOre(e.getMember(), nether);
int i;
if (nether) {
@@ -181,7 +178,7 @@ public class MineCommand extends CooldownCommand {
if (!e.getMessage().getContentRaw().equalsIgnoreCase(getPickString(ore)))
return false;
- if (oreLevel > levelToMaxOre(bot.getPickaxes().getPickaxeLevel(e.getMember())))
+ if (oreLevel > levelToMaxOre(bot.getPickaxe(e.getMember()).getLevel()))
return false;
return true;
@@ -235,6 +232,7 @@ public class MineCommand extends CooldownCommand {
Map<MineshaftItem, Long> awards = getAwards(member, ore);
bot.addItems(member, awards);
+ bot.getPlayerStats().getStat(MINED_STAT).increment(member);
String awardsList = bot.createItemList(awards, "+%s");
embedBuilder.setDescription(member.getAsMention() + " mined the ore!\n " + awardsList);
@@ -333,11 +331,11 @@ public class MineCommand extends CooldownCommand {
}
public double getEfficiencyCurve(Member m) {
- return 1 + Math.pow(0.5, bot.getPickaxes().getPickaxeEfficiency(m) / 2);
-
+ return 1 + Math.pow(0.5, bot.getPickaxe(m).getEfficiency() / 2);
}
+
private double getPickaxeFortuneCurve(Member m) {
- int fortune = bot.getPickaxes().getPickaxeFortune(m);
+ int fortune = bot.getPickaxe(m).getFortune();
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 41e4ce4..f2cbe4a 100644
--- a/src/main/java/net/uomc/mineshaft/Mineshaft.java
+++ b/src/main/java/net/uomc/mineshaft/Mineshaft.java
@@ -1,8 +1,14 @@
package net.uomc.mineshaft;
+import net.uomc.mineshaft.blacksmith.Armour;
+import net.uomc.mineshaft.blacksmith.BlacksmithCommand;
+import net.uomc.mineshaft.blacksmith.Pickaxe;
+import net.uomc.mineshaft.blacksmith.Sword;
+import net.uomc.mineshaft.blacksmith.Tools;
import net.uomc.mineshaft.crafting.Crafting;
import net.uomc.mineshaft.farm.CompostCommand;
import net.uomc.mineshaft.farm.FarmCommand;
+import net.uomc.mineshaft.farm.CampfireCommand;
import net.uomc.mineshaft.farm.TradeCommand;
import net.uomc.mineshaft.resources.Resource;
import java.io.IOException;
@@ -12,19 +18,17 @@ import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
-import java.util.concurrent.atomic.AtomicLong;
+import java.util.Optional;
import java.util.stream.Collectors;
import javax.security.auth.login.LoginException;
-import org.apache.commons.collections4.map.LinkedMap;
import org.json.JSONException;
import org.json.JSONObject;
import com.mouldycheerio.dbot.CustomBot;
import com.mouldycheerio.dbot.commands.AvatarCommand;
import com.mouldycheerio.dbot.commands.CommandDetails;
-import com.mouldycheerio.dbot.commands.DetailedCommand;
import com.mouldycheerio.dbot.commands.ProfileCommand;
import com.mouldycheerio.dbot.commands.ServerInfoCommand;
import com.mouldycheerio.dbot.commands.cooldowns.CooldownCommand;
@@ -33,7 +37,6 @@ import com.mouldycheerio.dbot.starboard.StarboardController;
import com.mouldycheerio.dbot.util.PeelingUtils;
import net.dv8tion.jda.api.entities.Member;
-import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.uomc.mineshaft.resources.ResourceManager;
import net.uomc.mineshaft.resources.market.MarketCommand;
@@ -42,7 +45,8 @@ public class Mineshaft extends CustomBot {
private StarboardController starboardController;
private FullLogger logger;
private ResourceManager resourceManager;
- private Pickaxes pickaxes;
+ private PlayerStats playerStats;
+ private Tools tools;
private Crafting crafting;
private MineCommand mineCommand;
private EnchantCommand enchantCommand;
@@ -51,7 +55,8 @@ public class Mineshaft extends CustomBot {
public Mineshaft(JSONObject config) throws LoginException, JSONException, IOException, InterruptedException {
super(config);
- pickaxes = new Pickaxes(this);
+ playerStats = new PlayerStats(this);
+ tools = new Tools(this);
healths = new PlayerHealths(this);
crafting = new Crafting(this);
getCommandController().addCommand(crafting);
@@ -81,6 +86,20 @@ public class Mineshaft extends CustomBot {
getCommandController().addCommand(new RobCommand(this));
getCommandController().addCommand(new TradeCommand(this));
+ // TODO remove this comand
+ getCommandController().addCommand(CommandDetails.from("setsword"), (e, b, args) -> {
+ List<String> argList = Arrays.asList(args);
+ Optional<Integer> level = argList.stream().filter(s -> PeelingUtils.isInteger(s))
+ .map(s -> Integer.parseInt(s)).findFirst();
+ getSword(e.getMember()).setLevel(level.get());
+ sendSuccessMessage(e, "Set sword level of " + e.getMember().getAsMention() + " to " + level.get());
+ });
+
+ // TODO remove this comand
+ getCommandController().addCommand(CommandDetails.from("getsword"), (e, b, args) -> {
+ sendSuccessMessage(e,
+ "" + e.getMember().getAsMention() + " has sword level: " + getSword(e.getMember()).getLevel());
+ });
getCommandController().removeCommand("help");
getCommandController().addCommand(CommandDetails.from("help"), (e, b, args) -> {
@@ -172,7 +191,10 @@ public class Mineshaft extends CustomBot {
getCommandController().addCommand(new MineshaftGiveResourcesCommand(this));
getCommandController().addCommand(new FarmCommand(this));
+ getCommandController().addCommand(new CampfireCommand(this));
getCommandController().addCommand(new CompostCommand(this));
+ getCommandController().addCommand(new EatCommand(this));
+ getCommandController().addCommand(new BlacksmithCommand(this));
logger = new FullLogger(this);
}
@@ -235,6 +257,14 @@ public class Mineshaft extends CustomBot {
return resourceManager.getResource(member, item.toString());
}
+ public boolean hasItem(Member member, MineshaftItem item) {
+ return getItem(member, item) > 0;
+ }
+
+ public String prettyValue(MineshaftItem item, long value) {
+ return getItem(item).prettyValue(value);
+ }
+
public Resource getItem(MineshaftItem item) {
return resourceManager.getResource(item.toString());
}
@@ -282,6 +312,7 @@ public class Mineshaft extends CustomBot {
public String createItemList(Map<MineshaftItem, Long> items) {
LinkedHashMap<MineshaftItem, Long> itemsLinked = new LinkedHashMap<>(items);
return resourceManager.createResourceList(itemsLinked.entrySet().stream()
+ .filter(e -> e.getValue() > 0)
.collect(Collectors.toMap(
e -> e.getKey().toString(),
Map.Entry::getValue
@@ -325,8 +356,23 @@ public class Mineshaft extends CustomBot {
}).reduce(Boolean.TRUE, Boolean::logicalAnd);
}
- public Pickaxes getPickaxes() {
- return pickaxes;
+ public PlayerStats getPlayerStats() {
+ return playerStats;
+ }
+ public Tools getTools() {
+ return tools;
+ }
+
+ public Pickaxe getPickaxe(Member member) {
+ return tools.getPickaxe(member);
+ }
+
+ public Sword getSword(Member member) {
+ return tools.getSword(member);
+ }
+
+ public Armour getArmour(Member member) {
+ return tools.getArmour(member);
}
public MineCommand getMineCommand() {
diff --git a/src/main/java/net/uomc/mineshaft/MineshaftGiveResourcesCommand.java b/src/main/java/net/uomc/mineshaft/MineshaftGiveResourcesCommand.java
index 553bb76..3d05ab7 100644
--- a/src/main/java/net/uomc/mineshaft/MineshaftGiveResourcesCommand.java
+++ b/src/main/java/net/uomc/mineshaft/MineshaftGiveResourcesCommand.java
@@ -82,7 +82,7 @@ public class MineshaftGiveResourcesCommand extends DetailedCommand {
return;
}
- if (bot.getPickaxes().isNether(member) != bot.getPickaxes().isNether(e.getMember())) {
+ if (bot.getPlayerStats().isNether(member) != bot.getPlayerStats().isNether(e.getMember())) {
op.sendErrorMessage(e, ":x: You can't give items to players in other dimensions!");
return;
}
diff --git a/src/main/java/net/uomc/mineshaft/MineshaftItem.java b/src/main/java/net/uomc/mineshaft/MineshaftItem.java
index 8956b93..90b6291 100644
--- a/src/main/java/net/uomc/mineshaft/MineshaftItem.java
+++ b/src/main/java/net/uomc/mineshaft/MineshaftItem.java
@@ -33,6 +33,11 @@ public enum MineshaftItem {
COMPOSTER,
BONEMEAL,
IRON_FARM,
+ CAMPFIRE,
+ BAKED_POTATO,
+ COOKED_FISH,
+ BLACKSMITH,
+ FORGE,
;
MineshaftItem() {
diff --git a/src/main/java/net/uomc/mineshaft/MineshaftLeaderBoardCommand.java b/src/main/java/net/uomc/mineshaft/MineshaftLeaderBoardCommand.java
index 91c9ef6..722b873 100644
--- a/src/main/java/net/uomc/mineshaft/MineshaftLeaderBoardCommand.java
+++ b/src/main/java/net/uomc/mineshaft/MineshaftLeaderBoardCommand.java
@@ -14,6 +14,7 @@ import com.mouldycheerio.dbot.commands.DetailedCommand;
import com.mouldycheerio.dbot.util.PeelingUtils;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
+import net.uomc.mineshaft.blacksmith.Pickaxe;
import net.uomc.mineshaft.resources.Resource;
public class MineshaftLeaderBoardCommand extends DetailedCommand {
@@ -33,26 +34,30 @@ public class MineshaftLeaderBoardCommand extends DetailedCommand {
if (resource == null) {
if (args[0].equalsIgnoreCase("pickaxes") || args[0].equalsIgnoreCase("pickaxe")) {
bot.sendMessage(e, "Leaderboard", makeMessage(
- bot.getPickaxes().getMembers(e.getGuild()), "pickaxe level",
+ bot.getPlayerStats().getStat(Pickaxe.LEVEL_TABLE).getMembers(e.getGuild()), "pickaxe level",
entry -> {
String ench = "";
- long level = bot.getPickaxes().getLevel(entry.getKey(), e.getGuild().getId());
- long fortune = bot.getPickaxes().getFortune(entry.getKey(), e.getGuild().getId());
- long efficiency = bot.getPickaxes().getEfficiency(entry.getKey(), e.getGuild().getId());
+ long level = bot.getPlayerStats().getStat(Pickaxe.LEVEL_TABLE).get(entry.getKey(), e.getGuild().getId());
+ long fortune = bot.getPlayerStats().getStat(Pickaxe.FORTUNE_TABLE).get(entry.getKey(), e.getGuild().getId());
+ long efficiency = bot.getPlayerStats().getStat(Pickaxe.FORTUNE_TABLE).get(entry.getKey(), e.getGuild().getId());
if (fortune > 0 || efficiency > 0) {
ench = String.format("(Eff%s,Fort%s)", efficiency, fortune);
}
- return Pickaxes.pickaxeLevelToName(level) + ench ;
+ return Pickaxe.pickaxeLevelToName(level) + ench ;
},
- user -> bot.getPickaxes().getLevel(user, e.getGuild().getId()) + bot.getPickaxes().getEfficiency(user, e.getGuild().getId()) + bot.getPickaxes().getFortune(user, e.getGuild().getId())));
+ user -> bot.getPlayerStats().getStat(Pickaxe.LEVEL_TABLE).get(user, e.getGuild().getId())
+ + bot.getPlayerStats().getStat(Pickaxe.EFFICIENCY_TABLE).get(user,
+ e.getGuild().getId())
+ + bot.getPlayerStats().getStat(Pickaxe.FORTUNE_TABLE).get(user,
+ e.getGuild().getId())));
return;
}
if (args[0].equalsIgnoreCase("farm") || args[0].equalsIgnoreCase("farmlevel")) {
bot.sendMessage(e, "Leaderboard", makeMessage(
- bot.getPickaxes().getMembers(e.getGuild()), "farm level",
+ bot.getPlayerStats().getStat(PlayerStats.FARM_LEVEL_TABLE).getMembers(e.getGuild()), "farm level",
entry -> PeelingUtils.amountToString(entry.getValue()),
- user -> bot.getPickaxes().getFarmLevel(user, e.getGuild().getId())
+ user -> bot.getPlayerStats().getFarmLevel(user, e.getGuild().getId())
));
return;
}
diff --git a/src/main/java/net/uomc/mineshaft/PickaxeCommand.java b/src/main/java/net/uomc/mineshaft/PickaxeCommand.java
index 31ac11c..a81ccd1 100644
--- a/src/main/java/net/uomc/mineshaft/PickaxeCommand.java
+++ b/src/main/java/net/uomc/mineshaft/PickaxeCommand.java
@@ -13,6 +13,7 @@ import net.dv8tion.jda.api.EmbedBuilder;
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.blacksmith.Pickaxe;
public class PickaxeCommand extends DetailedCommand {
@@ -26,10 +27,11 @@ public class PickaxeCommand extends DetailedCommand {
@Override
public void execute(MessageReceivedEvent e, CustomBot b, String[] args) throws CommandFail {
if (args.length > 0 && "upgrade".equalsIgnoreCase(args[0])) {
- int level = bot.getPickaxes().getPickaxeLevel(e.getMember());
- Map<MineshaftItem, Long> upgradeCost = upgradeCost(e.getMember());
+ Pickaxe pick = bot.getPickaxe(e.getMember());
+ int level = pick.getLevel();
+ Map<MineshaftItem, Long> upgradeCost = upgradeCost(pick);
- if (level >= bot.getPickaxes().getMaPickaxeLevel()) {
+ if (level >= pick.getMaxLevel()) {
bot.sendErrorMessage(e, ":x: Your pickaxe is already at the maximum level");
return;
}
@@ -42,31 +44,29 @@ public class PickaxeCommand extends DetailedCommand {
}
bot.removeItems(e.getMember(), upgradeCost);
- bot.getPickaxes().setLevel(e.getMember(), level + 1);
- String pickName = bot.getPickaxes().getPickaxeName(e.getMember());
+ pick.setLevel(level + 1);
+ String pickName = pick.getName();
bot.sendSuccessMessage(e, "Your pickaxe has been upgraded to a **" + pickName + " Pickaxe**");
return;
}
- String pickName = bot.getPickaxes().getPickaxeName(e.getMember());
- 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());
String p2 = target.equals(e.getMember()) ? "Your pickaxe" : String.format("%s's pickaxe", e.getMember().getEffectiveName());
+ Pickaxe pick = bot.getPickaxe(target);
+ String pickName = pick.getName();
+ String nextPick = pick.getNextName();
+ String pickImage = pick.getImage();
- Map<MineshaftItem, Long> upgradeCost = upgradeCost(target);
+ Map<MineshaftItem, Long> upgradeCost = upgradeCost(pick);
String upgradeString = "\n\nTo upgrade to a **" + nextPick + " Pickaxe **, use `" + bot.getCommandController().getPrefix() + "pickaxe upgrade`.\nUpgrade cost: **" + String.join(",", bot.createItemList(upgradeCost).split("\n")) + "**";
if (!target.equals(e.getMember())){
upgradeString = "";
}
- String enchants = String.format("\n%s ", p2) + bot.getEnchantCommand().getPickaxeEnchantmentsString(fortune, efficiency);
+ String enchants = String.format("\n%s ", p2) + pick.getEnchantmentString();
EmbedBuilder em = new EmbedBuilder();
em.setTitle(p2);
@@ -76,10 +76,10 @@ public class PickaxeCommand extends DetailedCommand {
e.getMessage().replyEmbeds(em.build()).queue();
}
- private Map<MineshaftItem, Long> upgradeCost(Member m) {
+ private Map<MineshaftItem, Long> upgradeCost(Pickaxe pick) {
Map<MineshaftItem, Long> cost = new HashMap<>();
- int level = bot.getPickaxes().getPickaxeLevel(m);
+ int level = pick.getLevel();
switch ((int) level) {
case 0:
diff --git a/src/main/java/net/uomc/mineshaft/Pickaxes.java b/src/main/java/net/uomc/mineshaft/Pickaxes.java
deleted file mode 100644
index 39fa030..0000000
--- a/src/main/java/net/uomc/mineshaft/Pickaxes.java
+++ /dev/null
@@ -1,276 +0,0 @@
-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;
-
-public class Pickaxes {
-
- public 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 = "farms";
-
- private String pickaxesDb;
-
- public Pickaxes(Mineshaft mineshaft) {
- pickaxesDb = (new File(mineshaft.getDatadir(), "pickaxes.db")).getPath();
- initDB();
- }
-
- private void initDB() {
- try {
- DatabaseUtils.createSimpleKVtable(pickaxesDb, FORTUNE_TABLE);
- } catch (SQLException e) {
- }
- 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) {
- try {
- DatabaseUtils.putInKVtable(pickaxesDb, LEVEL_TABLE, member.getId() + ":" + member.getGuild().getId(), value);
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
-
- 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<String> getMembersGuilds() {
- try {
- return DatabaseUtils.listKeys(pickaxesDb, LEVEL_TABLE);
- } catch (SQLException e) {
- e.printStackTrace();
- }
- return Collections.emptyList();
- }
-
- public List<String> 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 {
- 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);
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
-
- public long getFortune(String member, String guild) {
- try {
- 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;
- }
-
- public String getPickaxeName(Member member) {
- long level = getLevel(member);
- return pickaxeLevelToName(level);
- }
-
- public String getNextPickaxeName(Member member) {
- long level = getLevel(member) + 1;
- if (level == getMaPickaxeLevel())
- level = getMaPickaxeLevel();
- return pickaxeLevelToName(level);
- }
-
- public static String pickaxeLevelToName(long level) {
- switch ((int) level) {
- case 0:
- return "Stone";
- case 1:
- return "Copper";
- case 2:
- return "Iron";
- case 3:
- return "Gold";
- case 4:
- return "Diamond";
- default:
- return "Netherite";
- }
- }
-
- public String getPickaxeImage(Member member) {
- long level = getLevel(member);
- switch ((int) level) {
- case 0:
- return isEnchanted(member) ?
- "https://minecraft.wiki/images/Enchanted_Stone_Pickaxe.gif"
- : "https://minecraft.wiki/images/Stone_Pickaxe_JE2_BE2.png";
- case 1:
- return isEnchanted(member) ?
- "https://minecraft.wiki/images/Enchanted_Copper_Pickaxe.webp"
- : "https://minecraft.wiki/images/Copper_Pickaxe_JE1_BE1.png";
- case 2:
- return isEnchanted(member) ?
- "https://minecraft.wiki/images/Enchanted_Iron_Pickaxe.gif"
- : "https://minecraft.wiki/images/Iron_Pickaxe_JE3_BE2.png";
- case 3:
- return isEnchanted(member) ?
- "https://minecraft.wiki/images/Enchanted_Golden_Pickaxe.gif"
- : "https://minecraft.wiki/images/Golden_Pickaxe_JE4_BE3.png";
- case 4:
- return isEnchanted(member) ?
- "https://minecraft.wiki/images/Enchanted_Diamond_Pickaxe.gif"
- : "https://minecraft.wiki/images/Diamond_Pickaxe_JE3_BE3.png";
- default:
- return isEnchanted(member) ?
- "https://minecraft.wiki/images/Netherite_Pickaxe_JE3.png"
- : "https://minecraft.wiki/images/Enchanted_Netherite_Pickaxe.gif";
- }
- }
-
- public int getMaPickaxeLevel() {
- return MAX_PICKAXE_LEVEL;
- }
-
- public int getPickaxeLevel(Member member) {
- return (int) getLevel(member);
- }
-
- public int getPickaxeFortune(Member member) {
- 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")
- .replace("IIII", "IV")
- .replace("VV", "X")
- .replace("VIV", "IX")
- .replace("XXXXX", "L")
- .replace("XXXX", "XL")
- .replace("LL", "C")
- .replace("LXL", "XC")
- .replace("CCCCC", "D")
- .replace("CCCC", "CD")
- .replace("DD", "M")
- .replace("DCD", "CM");
- }
-
-}
diff --git a/src/main/java/net/uomc/mineshaft/PlayerHealths.java b/src/main/java/net/uomc/mineshaft/PlayerHealths.java
index 395f71a..0b3af79 100644
--- a/src/main/java/net/uomc/mineshaft/PlayerHealths.java
+++ b/src/main/java/net/uomc/mineshaft/PlayerHealths.java
@@ -1,13 +1,12 @@
package net.uomc.mineshaft;
-import java.io.File;
-import java.sql.SQLException;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
+import java.util.Collections;
import com.mouldycheerio.dbot.commands.CommandDetails;
-import com.mouldycheerio.dbot.util.DatabaseUtils;
import com.mouldycheerio.dbot.util.PeelingUtils;
import com.vdurmont.emoji.EmojiManager;
import com.vdurmont.emoji.EmojiParser;
@@ -21,43 +20,41 @@ import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
public class PlayerHealths {
private static final String HP_TABLE = "hp";
- private static final String HP_EMOJI = "<:hp:1428837195329962115>";
- private String healthDb;
+ public static final String HP_EMOJI = "<:hp:1428837195329962115>";
private Mineshaft bot;
- private static final long MAX_HP = 20;
+ public static final long MAX_HP = 20;
+
+ private SavedStat healthStat;
public PlayerHealths(Mineshaft bot) {
this.bot = bot;
- healthDb = (new File(bot.getDatadir(), "players.db")).getPath();
- initDB();
+ healthStat = bot.getPlayerStats().getStat(HP_TABLE);
+ healthStat.setDefaultValue(MAX_HP);
bot.getCommandController().addCommand(CommandDetails.from("hp,health"), (e, b, args) -> {
Member member = PeelingUtils.getSingleMentionFromArgs(e);
+
+
+ if (e.getMember().getId().equals(b.getOwnerID())){
+ Optional<Long> amount = Arrays.asList(args).stream().filter(s -> PeelingUtils.isLong(s)).map(s -> Long.parseLong(s))
+ .findFirst();
+ if (!amount.isEmpty()) {
+ setHP(member, amount.get());
+ }
+ }
+
b.sendMessage(e, member.getEffectiveName() + "'s health", (member.equals(e.getMember()) ? "Your " : member.getEffectiveName() + "'s") + " health: " + getHPString(member));
});
}
public void setHP(Member member, long value) {
- try {
- DatabaseUtils.putInKVtable(healthDb, HP_TABLE, member.getId() + ":" + member.getGuild().getId(), value);
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
-
- private long getHP(String member, String guild) {
- try {
- return DatabaseUtils.getInKVtable(healthDb, HP_TABLE, member + ":" + guild);
- } catch (SQLException e) {
- e.printStackTrace();
- }
- return MAX_HP;
+ healthStat.set(member, value);
}
public long getHP(Member member) {
- return getHP(member.getId(), member.getGuild().getId());
+ return healthStat.get(member);
}
public String getHPString(Member member) {
@@ -68,65 +65,82 @@ public class PlayerHealths {
return "**" + hp + HP_EMOJI + "**";
}
- public long damage(MessageReceivedEvent event, Member member, long amount, String reason) {
- long hp = getHP(member);
- hp -= amount;
- if (hp <= 0) {
- killPlayer(event, member, reason);
- setHP(member, MAX_HP);
- } else {
- setHP(member, hp);
+ public long calculateDamage(Member member, long damage) {
+ return calculateDamage(member, null, true, damage);
+ }
+
+ public long calculateDamage(Member member, boolean countArmour, long damage) {
+ return calculateDamage(member, null, countArmour, damage);
+ }
+
+ public long calculateDamage(Member target, Member attacker, boolean countArmour, long damage) {
+ return calculateDamage(target, attacker, countArmour, true, damage);
+ }
+
+ public long calculateDamage(Member target, Member attacker, boolean countArmour, boolean randomise, long damage) {
+ long bonus = 0;
+ if (attacker != null) {
+ bonus = bot.getSword(attacker).getDamageBonus();
}
- return hp;
+ double n = 1;
+
+ if (randomise) {
+ n = Math.random();
+ }
+
+ return (long) (n * Math.abs(damage)) + bonus - bot.getArmour(target).getDamageReduction();
+ }
+
+ public long damage(MessageReceivedEvent event, Member member, long amount, String reason) {
+ return damageAndDropIfKill(event, member, amount, reason, Collections.emptyMap());
}
public long damageAndDropIfKill(MessageReceivedEvent event, Member member, long amount, String reason, Map<MineshaftItem, Long> items) {
- long hp = getHP(member);
- hp -= amount;
- if (hp <= 0) {
- killPlayerAndDrop(event, member, reason, items);
- setHP(member, MAX_HP);
- } else {
+
+ long hp = getHP(member) - amount;
+
+ if (hp > 0) {
setHP(member, hp);
+ return hp;
}
+
+ killPlayerAndDrop(event, member, reason, items);
+
return hp;
}
public long damageAndDropIfKill(Message message, Member member, long amount, String reason, Map<MineshaftItem, Long> items) {
long hp = getHP(member);
hp -= amount;
- if (hp <= 0) {
- killPlayerAndDrop(message, member, reason, items);
- setHP(member, MAX_HP);
- } else {
+
+ if (hp > 0) {
setHP(member, hp);
+ return hp;
}
+
+ killPlayerAndDrop(message, member, reason, items);
return hp;
}
public long damage(Message message, Member member, long amount, String reason) {
- long hp = getHP(member);
- hp -= amount;
- if (hp <= 0) {
- killPlayer(message, member, reason);
- setHP(member, MAX_HP);
- } else {
+ long hp = getHP(member) - amount;
+
+ if (hp > 0) {
setHP(member, hp);
+ return hp;
}
- return hp;
- }
- private void initDB() {
- try {
- DatabaseUtils.createSimpleKVtable(healthDb, HP_TABLE);
- } catch (SQLException e) {
- }
+ killPlayer(message, member, reason);
+ return hp;
}
public void killPlayerAndDrop(Message message, Member member, String deathMessage, Map<MineshaftItem, Long> items) {
+ setHP(member, MAX_HP);
Map<MineshaftItem, Long> drops = DropUtil.getDeathDrops(bot, member);
- drops = bot.sumItems(drops, items);
+
+ if (!items.isEmpty())
+ drops = bot.sumItems(drops, items);
bot.removeItems(member, drops);
@@ -137,6 +151,7 @@ public class PlayerHealths {
DropUtil.spawnDropEdit(bot, message, embed, drops);
return;
}
+
String title = getDeathTitle(member, deathMessage);
MessageEmbed embed = DropUtil.getDropEmbed(bot, drops, deathMessage, title);
@@ -148,10 +163,10 @@ public class PlayerHealths {
}
public void killPlayer(MessageReceivedEvent event, Member member, String deathMessage ) {
- killPlayerAndDrop(event, member, deathMessage, new HashMap<>());
+ killPlayerAndDrop(event, member, deathMessage, Collections.emptyMap());
}
public void killPlayer(Message message, Member member, String deathMessage ) {
- killPlayerAndDrop(message, member, deathMessage, new HashMap<>());
+ killPlayerAndDrop(message, member, deathMessage, Collections.emptyMap());
}
private String getDeathTitle(Member member, String deathMessage) {
diff --git a/src/main/java/net/uomc/mineshaft/PlayerStats.java b/src/main/java/net/uomc/mineshaft/PlayerStats.java
new file mode 100644
index 0000000..40ef349
--- /dev/null
+++ b/src/main/java/net/uomc/mineshaft/PlayerStats.java
@@ -0,0 +1,80 @@
+package net.uomc.mineshaft;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+import net.dv8tion.jda.api.entities.Member;
+
+public class PlayerStats {
+
+ public static final int MAX_PICKAXE_LEVEL = 5;
+
+ public static final String DIMENSION_TABLE = "dimension";
+ public static final String FARM_LEVEL_TABLE = "farms";
+
+ private String playersDb;
+
+ private Map<String, SavedStat> stats;
+
+ public PlayerStats(Mineshaft mineshaft) {
+ File playersDbFile = new File(mineshaft.getDatadir(), "players.db");
+
+ // migrate old file if exists
+ if (!playersDbFile.exists()) {
+ File oldplayersDbFile = new File(mineshaft.getDatadir(), "pickaxes.db");
+ if (oldplayersDbFile.exists()) {
+ oldplayersDbFile.renameTo(playersDbFile);
+ }
+ }
+
+ stats = new HashMap<>();
+
+ playersDb = playersDbFile.getPath();
+ initStats();
+ }
+
+ private void initStats() {
+ createStat(DIMENSION_TABLE);
+ createStat(FARM_LEVEL_TABLE);
+ }
+
+ public SavedStat createStat(String name) {
+ SavedStat savedStat = new SavedStat(playersDb, name);
+ stats.put(name, savedStat);
+ return savedStat;
+ }
+
+
+ public SavedStat getStat(String name) {
+ if (stats.containsKey(name))
+ return stats.get(name);
+
+ SavedStat savedStat = new SavedStat(playersDb, name);
+ stats.put(name, savedStat);
+ return savedStat;
+ }
+
+ public void setFarmLevel(Member member, long value) {
+ getStat(FARM_LEVEL_TABLE).set(member, value);
+ }
+
+ public long getFarmLevel(String member, String guild) {
+ return getStat(FARM_LEVEL_TABLE).get(member, guild);
+ }
+
+ public long getFarmLevel(Member member) {
+ return getFarmLevel(member.getId(), member.getGuild().getId());
+ }
+
+ public void setNether(Member member, boolean nether) {
+ getStat(DIMENSION_TABLE).set(member, nether ? 1 : 0);
+ }
+
+ public boolean isNether(Member member) {
+ return getStat(DIMENSION_TABLE).get(member) == 1;
+ }
+
+ public String getDbPath() {
+ return playersDb;
+ }
+}
diff --git a/src/main/java/net/uomc/mineshaft/Portal.java b/src/main/java/net/uomc/mineshaft/Portal.java
index 2d3df02..499bdb4 100644
--- a/src/main/java/net/uomc/mineshaft/Portal.java
+++ b/src/main/java/net/uomc/mineshaft/Portal.java
@@ -53,13 +53,13 @@ public class Portal extends CooldownCommand {
em.setColor(PeelingUtils.hex2Rgb("#8947e8"));
em.setThumbnail(COMMAND_IMAGE);
- if (bot.getPickaxes().isNether(e.getMember())) {
- bot.getPickaxes().setNether(e.getMember(), false);
+ if (bot.getPlayerStats().isNether(e.getMember())) {
+ bot.getPlayerStats().setNether(e.getMember(), false);
em.setDescription("You go through the potal... everything is back to normal\n\n**You are now in the overworld**");
em.setImage(OVERWORLD_IMAGE);
} else {
- bot.getPickaxes().setNether(e.getMember(), true);
+ bot.getPlayerStats().setNether(e.getMember(), true);
em.setDescription("You go through the potal... things look different on this side...\n\n**You are now in the nether**");
em.setFooter(COMMAND_IMAGE);
em.setImage(NETHER_IMAGE);
diff --git a/src/main/java/net/uomc/mineshaft/RobCommand.java b/src/main/java/net/uomc/mineshaft/RobCommand.java
index ace95e7..bfc0c51 100644
--- a/src/main/java/net/uomc/mineshaft/RobCommand.java
+++ b/src/main/java/net/uomc/mineshaft/RobCommand.java
@@ -1,47 +1,41 @@
package net.uomc.mineshaft;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.Map;
import java.util.Optional;
-import java.util.Random;
import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
-
-import org.jetbrains.annotations.NotNull;
+import java.util.function.Consumer;
import com.mouldycheerio.dbot.commands.CommandDetails;
import com.mouldycheerio.dbot.commands.cooldowns.CooldownCommand;
-import com.mouldycheerio.dbot.util.PeelingUtils;
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.MessageEmbed;
-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;
public class RobCommand extends CooldownCommand {
- private static final long DROP_DURATION_SECONDS = 90;
- private static final String LOOT_STRING = "loot";
-
- private static final long MAX_DAMAGE = 20;
+ private static final UnicodeEmoji FLEE_EMOJI = Emoji.fromUnicode(EmojiParser.parseToUnicode(":runner:"));
+ private static final UnicodeEmoji FIGHT_EMOJI = Emoji.fromUnicode(EmojiParser.parseToUnicode(":crossed_swords:"));
+ private static final long BASE_DAMAGE = 14;
+ private static final long CONFIRM_WAIT_SECONDS = 10;
+ private static final double FLEE_CHANCE = 0.3;
private Mineshaft bot;
- private @NotNull String embedTitle;
- private @NotNull String pvpEmoji;
+ private String pvpEmoji;
protected RobCommand(Mineshaft bot) {
super(bot);
- setCooldown(60l * 30l * 1000l);
+ // TODO reset this
+ // setCooldown(60l * 30l * 1000l);
+ setCooldown(0l);
this.bot = bot;
- setDetails(CommandDetails.from("kill,pvp,rob", "kill another player"));
- embedTitle = EmojiParser.parseToUnicode(":crossed_swords:");
+ setDetails(CommandDetails.from("kill,pvp,rob,fight,challenge", "kill another player"));
pvpEmoji = EmojiParser.parseToUnicode(":crossed_swords:");
}
@@ -59,36 +53,144 @@ public class RobCommand extends CooldownCommand {
return false;
}
Member target = mentionToMember.get();
+ if (target.equals(e.getMember())) {
+ e.getMessage().reply(":x: You cannot fight yourself!").queue();
+ return false;
+ }
- 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();
+ if (!canFight(e.getMember())) {
+ e.getMessage().reply(":x: You tried to kill " + target.getAsMention()
+ + " you don't have a sword to fight with!\nUse `m!blacksmith` to forge one").queue();
+ return false;
+ }
+
+ if (bot.getPlayerStats().isNether(target) != bot.getPlayerStats().isNether(e.getMember())) {
+ e.getMessage().reply(
+ ":x: You tried to kill " + target.getAsMention() + " but they were in a different dimension!")
+ .queue();
return false;
}
e.getMessage().addReaction(Emoji.fromUnicode(pvpEmoji)).queue();
EmbedBuilder eb = new EmbedBuilder();
- eb.setTitle(pvpEmoji);
- eb.getDescriptionBuilder().append(e.getAuthor().getAsMention() + " is fighting " + target.getAsMention() + "..." );
+ eb.setTitle("pvp");
+ String startString = e.getAuthor().getAsMention() + " is fighting " + target.getAsMention() + "...\n\n";
+ eb.getDescriptionBuilder().append(startString);
+
+ eb.appendDescription(target.getAsMention() + ": React with " + FLEE_EMOJI.getFormatted() + " to flee");
+ if (canFight(target)) {
+ eb.appendDescription(" or " + FIGHT_EMOJI.getFormatted() + " to fight back!");
+ }
+
+ eb.appendDescription("\n");
+ eb.appendDescription(":warning: This chance will expire "
+ + PeelingUtils.formatTimeRelativeFromNow(CONFIRM_WAIT_SECONDS * 1000l) + "\n");
+
eb.setColor(bot.color);
- long damage = getDamage(e.getMember());
+ long damage = bot.getHealths().calculateDamage(target, e.getMember(), false, BASE_DAMAGE);
+
+ e.getMessage().replyEmbeds(eb.build()).queue(message -> {
+
+ message.addReaction(FLEE_EMOJI).queue();
+ if (canFight(target)) {
+ message.addReaction(FIGHT_EMOJI).queue();
+ }
+
+ message.addReaction(FLEE_EMOJI).queue((Void ignored) -> {
+ EventWaiter eventWaiter = new EventWaiter();
+ e.getChannel().getJDA().addEventListener(eventWaiter);
+
+ eventWaiter.waitForEvent(MessageReactionAddEvent.class,
+ e1 -> e1.getMessageId().equals(message.getId()) && e1.getUser().getId().equals(target.getId())
+ && (FLEE_EMOJI.equals(e1.getReaction().getEmoji().asUnicode())
+ || FIGHT_EMOJI.equals(e1.getReaction().getEmoji().asUnicode())),
+ e1 -> {
+ message.clearReactions().queue();
+ eb.setDescription(startString);
+
+ // target has a chance to evade the battle entirely
+ if (FLEE_EMOJI.equals(e1.getReaction().getEmoji().asUnicode())) {
+ if (Math.random() < FLEE_CHANCE) {
+ eb.appendDescription(FLEE_EMOJI.getFormatted() + target.getAsMention()
+ + " Managed to escape!\n");
+ message.editMessageEmbeds(eb.build()).queueAfter(1, TimeUnit.SECONDS, m -> {
+ m.editMessageEmbeds(eb.build()).queue();
+ });
+ return;
+
+ } else {
+ // fight happens anyway, if they can fight they will fight second
+ eb.appendDescription(
+ ":x:" + target.getAsMention() + " tried running away but failed!\n\n");
+ message.editMessageEmbeds(eb.build()).queueAfter(1, TimeUnit.SECONDS, m1 -> {
+ fightBack(m1, e.getMember(), target, damage, eb);
+ });
+ return;
+ }
+ }
+
+ // target gets to fight first then attacker fights
+ if (FIGHT_EMOJI.equals(e1.getReaction().getEmoji().asUnicode()) && canFight(target)) {
+ eb.appendDescription(FIGHT_EMOJI.getFormatted() + target.getAsMention()
+ + " Anticipated the attack and got the first strike\n");
+ message.editMessageEmbeds(eb.build()).queueAfter(1, TimeUnit.SECONDS, m1 -> {
+ fightBack(m1, target, e.getMember(), damage, eb);
+ });
+ return;
+ }
+
+ // attacker gets an attack and thats it
+ addFightMessage(message, target, e.getMember(), eb, damage, null);
+ }, CONFIRM_WAIT_SECONDS, TimeUnit.SECONDS, () -> {
+ message.clearReactions().queue();
+ eb.setDescription(startString);
+ message.editMessageEmbeds(eb.build()).queueAfter(1, TimeUnit.SECONDS, m -> {
+ // attacker gets an attack (ambush)
+ addFightMessage(m, target, e.getMember(), eb, damage, null);
+ });
+ });
+ });
+ });
+ return true;
+ }
+
+ public void fightBack(Message message, Member target, Member agressor, long attackerDamage, EmbedBuilder eb) {
+ long damage = bot.getHealths().calculateDamage(agressor, target, false, BASE_DAMAGE);
+
+ addFightMessage(message, agressor, target, eb, damage, m -> {
+ addFightMessage(message, target, agressor, eb, attackerDamage, null);
+ });
+ }
+
+ public void addFightMessage(Message message, Member target, Member attacker, EmbedBuilder eb, long damage,
+ Consumer<Message> callback) {
+
String damageString = " (" + PlayerHealths.getHPString(-damage) + ")";
- e.getMessage().replyEmbeds(eb.build()).delay(5, TimeUnit.SECONDS, e.getJDA().getRateLimitPool()).flatMap(m -> {
- String deathMessage = pvpEmoji + target.getAsMention() + " was slain by " + e.getAuthor().getAsMention()
- + damageString;
- long hp = bot.getHealths().damage(m, target, damage, deathMessage);
- return hp > 0;
- }, m -> {
- eb.setDescription(e.getAuthor().getAsMention() + " attacked " + target.getAsMention() + damageString
- + "\n\n" + "They are now on " + bot.getHealths().getHPString(target));
- return m.editMessageEmbeds(eb.build());
- }).queue();
- return true;
+ String swordEmoji = bot.getSword(attacker).getEmoji();
+ String deathMessage = swordEmoji + target.getAsMention() + " was slain by " + attacker.getAsMention()
+ + damageString;
+ long hp = bot.getHealths().damage(message, target, damage, deathMessage);
+
+ if (hp <= 0) {
+ return;
+ }
+
+ eb.appendDescription(
+ swordEmoji + attacker.getAsMention() + " attacked " + target.getAsMention() + damageString + "\n");
+
+ if (callback != null) {
+ message.editMessageEmbeds(eb.build()).queue(callback);
+ } else {
+ eb.appendDescription("\n" + target.getAsMention() + " is now on " + bot.getHealths().getHPString(target));
+ message.editMessageEmbeds(eb.build()).queue();
+ }
+ return;
}
- private long getDamage(Member member) {
- return (long) Math.ceil(MAX_DAMAGE * Math.random());
+ public boolean canFight(Member member) {
+ return bot.getSword(member).getLevel() != 0;
}
}
diff --git a/src/main/java/net/uomc/mineshaft/SavedStat.java b/src/main/java/net/uomc/mineshaft/SavedStat.java
new file mode 100644
index 0000000..01718d5
--- /dev/null
+++ b/src/main/java/net/uomc/mineshaft/SavedStat.java
@@ -0,0 +1,81 @@
+package net.uomc.mineshaft;
+
+import java.sql.SQLException;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import com.mouldycheerio.dbot.util.DatabaseUtils;
+
+import net.dv8tion.jda.api.entities.Guild;
+import net.dv8tion.jda.api.entities.Member;
+
+public class SavedStat {
+ private long defaultValue = 0l;
+ private String dbPath;
+ private String tableName;
+
+ public SavedStat(String dbPath, String tableName) {
+ this.dbPath = dbPath;
+ this.tableName = tableName;
+ createTable();
+ }
+
+ private void createTable() {
+ try {
+ DatabaseUtils.createSimpleKVtable(dbPath, tableName);
+ } catch (SQLException e) {
+ }
+ }
+
+ public void set(Member member, long value) {
+ try {
+ DatabaseUtils.putInKVtable(dbPath, tableName, member.getId() + ":" + member.getGuild().getId(), value);
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public long get(String member, String guild) {
+ try {
+ return DatabaseUtils.getInKVtable(dbPath, tableName, member + ":" + guild);
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ return defaultValue;
+ }
+
+ public long get(Member member) {
+ return get(member.getId(), member.getGuild().getId());
+ }
+
+ public List<String> getMembers(Guild guild) {
+ return getMembersGuilds().stream().filter(m -> guild.getId().equals(m.split(":")[1])).map(m -> m.split(":")[0]).collect(Collectors.toList());
+ }
+
+ public List<String> getMembersGuilds() {
+ try {
+ return DatabaseUtils.listKeys(dbPath, tableName);
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ return Collections.emptyList();
+ }
+
+ public long getDefaultValue() {
+ return defaultValue;
+ }
+
+ public void setDefaultValue(long defaultValue) {
+ this.defaultValue = defaultValue;
+ }
+
+ public void increment(Member member, long amount) {
+ set(member, get(member) + amount);
+ }
+
+ public void increment(Member member) {
+ set(member, get(member) + 1);
+ }
+
+}
diff --git a/src/main/java/net/uomc/mineshaft/SleepCommand.java b/src/main/java/net/uomc/mineshaft/SleepCommand.java
index ef97b8b..389e78b 100644
--- a/src/main/java/net/uomc/mineshaft/SleepCommand.java
+++ b/src/main/java/net/uomc/mineshaft/SleepCommand.java
@@ -4,6 +4,7 @@ import java.awt.Color;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.TimeUnit;
import org.jetbrains.annotations.NotNull;
@@ -26,7 +27,7 @@ public class SleepCommand extends CooldownCommand {
private static final int MAX_ITEMS_DROP = 10;
private static final int MIN_ITEMS_DROP = 3;
private static final long MAX_DAMAGE = 30;
- private static final long MIN_DAMAGE = 20;
+ private static final long MIN_DAMAGE = 19;
private Mineshaft bot;
private static final String damageEmoji = EmojiParser.parseToUnicode(":fire:");
@@ -52,7 +53,7 @@ public class SleepCommand extends CooldownCommand {
return false;
}
- if (bot.getPickaxes().isNether(e.getMember())) {
+ if (bot.getPlayerStats().isNether(e.getMember())) {
long damage = (long) Math.ceil((MAX_DAMAGE-MIN_DAMAGE)*Math.random() + MIN_DAMAGE);
String actionString = "Your bed exploded! " + PlayerHealths.getHPString(-damage) + "\n";
EmbedBuilder em = new EmbedBuilder();
@@ -63,24 +64,28 @@ public class SleepCommand extends CooldownCommand {
bot.removeItem(e.getMember(), MineshaftItem.BED, 1);
- e.getChannel().sendMessageEmbeds(em.build()).queue(m -> {
+ e.getMessage().replyEmbeds(em.build()).queue(m -> {
int itemsDrop = (int) (Math.random() * (MAX_ITEMS_DROP-MIN_ITEMS_DROP) + MIN_ITEMS_DROP);
Map<MineshaftItem, Long> award = new LinkedHashMap<>();
for (int i = 0; i < itemsDrop; ++i) {
- award = bot.sumItems(award,
+ award.putAll(bot.sumItems(award,
bot.getMineCommand().getAwards(null,
bot.getMineCommand().getOre(
- null, true)));
+ null, true))));
}
long finalHP = bot.getHealths().damageAndDropIfKill(m, e.getMember(), damage, damageEmoji + " " + e.getMember().getAsMention() + " died to Intentional Game Design", award);
if (finalHP > 0) {
- bot.addItems(e.getMember(), award);
+ em.appendDescription(bot.createItemList(award, "+%s"));
- MessageEmbed embed = DropUtil.getDropEmbed(bot, award, em.build());
- DropUtil.spawnDropEdit(bot, m, embed, award);
+ m.editMessageEmbeds(em.build()).queueAfter(2, TimeUnit.SECONDS, m2 -> {
+ bot.addItems(e.getMember(), award);
+ });
+
+ //MessageEmbed embed = DropUtil.getDropEmbed(bot, award, em.build());
+ //DropUtil.spawnDropEdit(bot, m, embed, award);
}
});
diff --git a/src/main/java/net/uomc/mineshaft/blacksmith/Armour.java b/src/main/java/net/uomc/mineshaft/blacksmith/Armour.java
new file mode 100644
index 0000000..592a4c3
--- /dev/null
+++ b/src/main/java/net/uomc/mineshaft/blacksmith/Armour.java
@@ -0,0 +1,54 @@
+package net.uomc.mineshaft.blacksmith;
+
+import net.dv8tion.jda.api.entities.Member;
+import net.uomc.mineshaft.Mineshaft;
+
+public class Armour extends Tool {
+ public static final int MAX_ARMOUR_LEVEL = 5;
+
+ public Armour(Mineshaft mineshaft, Member member) {
+ super(mineshaft, member, "armour");
+ }
+
+ public String getName() {
+ return armourLevelToName(getLevel());
+ }
+
+ public static String armourLevelToName(long level) {
+ switch ((int) level) {
+ case 0:
+ return "None";
+ case 1:
+ return "Copper";
+ case 2:
+ return "Iron";
+ case 3:
+ return "Gold";
+ case 4:
+ return "Diamond";
+ default:
+ return "Netherite";
+ }
+ }
+ public int getMaxLevel() {
+ return MAX_ARMOUR_LEVEL;
+ }
+
+ public long getDamageReduction() {
+ switch ((int) getLevel()) {
+ case 0: // "None";
+ return 0;
+ case 1: // "Copper";
+ return 3;
+ case 2: // "Iron";
+ return 6;
+ case 3: // "Gold";
+ return 9;
+ case 4: // "Diamond";
+ return 12;
+ default: // "Netherite";
+ return 15;
+ }
+ }
+
+}
diff --git a/src/main/java/net/uomc/mineshaft/blacksmith/Blacksmith.java b/src/main/java/net/uomc/mineshaft/blacksmith/Blacksmith.java
new file mode 100644
index 0000000..be3ad3c
--- /dev/null
+++ b/src/main/java/net/uomc/mineshaft/blacksmith/Blacksmith.java
@@ -0,0 +1,320 @@
+package net.uomc.mineshaft.blacksmith;
+
+import java.util.Map;
+
+import org.apache.commons.math3.distribution.BinomialDistribution;
+
+import com.mouldycheerio.dbot.util.PeelingUtils;
+
+import java.util.Collections;
+
+import net.dv8tion.jda.api.entities.Member;
+import net.uomc.mineshaft.Mineshaft;
+import net.uomc.mineshaft.MineshaftItem;
+import net.uomc.mineshaft.SavedStat;
+import net.uomc.mineshaft.farm.Farm;
+
+class Blacksmith extends Farm {
+
+ public static long UPDATES_PER_LEVEL = 10;
+ public static long MS_PER_UPDATE = 1000l * 60l * 10l;
+ private SavedStat questionsStat;
+
+ public Blacksmith(Mineshaft bot) {
+ super(bot, MineshaftItem.BLACKSMITH);
+ questionsStat = getBot().getPlayerStats().getStat("blacksmith_questions");
+ }
+
+ public boolean upgradeArmour(Member member) {
+ int armourLevel = getBot().getArmour(member).getLevel();
+ if (armourLevel >= Armour.MAX_ARMOUR_LEVEL) {
+ return false;
+ }
+ armourLevel += 1;
+
+ setPlanted(member, -armourLevel);
+
+ getBot().getArmour(member).setLevel(0);
+
+ setQuantity(member, armourLevel * UPDATES_PER_LEVEL);
+ return true;
+ }
+
+ public boolean upgradeSword(Member member) {
+ int swordLevel = getBot().getSword(member).getLevel();
+ if (swordLevel >= Sword.MAX_SWORD_LEVEL) {
+ return false;
+ }
+ swordLevel += 1;
+
+ setPlanted(member, -swordLevel);
+
+ getBot().getSword(member).setLevel(0);
+
+ setQuantity(member, swordLevel * UPDATES_PER_LEVEL);
+ return true;
+ }
+
+
+ public boolean isWorking(Member member) {
+ return getPlanted(member) != 0;
+ }
+
+ public boolean isSword(Member member) {
+ return getPlanted(member) > 0;
+ }
+
+ public int getWorkingLevel(Member member) {
+ return (int) Math.abs(getPlanted(member));
+ }
+
+ public boolean canUpgradeSword(Member member) {
+ return getBot().getSword(member).getLevel() < Sword.MAX_SWORD_LEVEL;
+ }
+
+ public boolean canUpgradeArmour(Member member) {
+ return getBot().getArmour(member).getLevel() < Armour.MAX_ARMOUR_LEVEL;
+ }
+
+ public String getNextSwordName(Member member) {
+ return Sword.swordLevelToName(getBot().getSword(member).getLevel() + 1) + " Sword";
+ }
+
+ public String getNextArmourName(Member member) {
+ return Armour.armourLevelToName(getBot().getArmour(member).getLevel() + 1) + " Armour";
+ }
+
+ public String getWorkingName(Member member) {
+ if (!isWorking(member)) {
+ return "";
+ }
+
+ if (isSword(member)) {
+ return Sword.swordLevelToName(getWorkingLevel(member)) + " Sword";
+ }
+
+ return Armour.armourLevelToName(getWorkingLevel(member)) + " Armour";
+ }
+
+ public void update(Member member) {
+ if (!isWorking(member))
+ return;
+
+ long next = getNextUpdate(member);
+ long now = System.currentTimeMillis();
+ if (next == 0) {
+ next = now;
+ }
+
+ if (next > now)
+ return;
+
+ long since = now - next;
+ long updates = since / MS_PER_UPDATE;
+
+ if (updates < 1) {
+ return;
+ }
+
+ BinomialDistribution bd = new BinomialDistribution((int) updates, getProgressChance(member));
+ setQuantity(member, getQuantity(member) - bd.sample());
+
+ setNextUpdate(member, getNextUpdate(member) + MS_PER_UPDATE*updates);
+ }
+
+ public double getProgressChance(Member member) {
+ long forges = getValidForgeCount(member);
+
+ if (forges < 1) {
+ return 0.0;
+ }
+
+ return 1 - (0.5 * Math.pow(forges, -0.5));
+ }
+
+ public long getValidForgeCount(Member member) {
+ long forges = getBot().getItem(member, MineshaftItem.FORGE);
+ long blacksmiths = getBot().getItem(member, MineshaftItem.BLACKSMITH);
+ return Math.min(forges, blacksmiths);
+ }
+
+ public double getProgress(Member member) {
+ if (!isWorking(member))
+ return 0.0;
+
+ long max = getWorkingLevel(member) * UPDATES_PER_LEVEL;
+ long current = getQuantity(member);
+ return (max - Math.min(current, 0)) / max;
+ }
+
+ public long getTimeEstimate(Member member, long updates) {
+ return (long) (MS_PER_UPDATE * (1 - getProgressChance(member)) * updates);
+ }
+
+ public long getTimeEstimateRemaining(Member member) {
+ return getTimeEstimate(member, getQuantity(member));
+ }
+
+ public long getTimeEstimateForNextArmour(Member member) {
+ int armourLevel = getBot().getArmour(member).getLevel();
+ return getTimeEstimate(member, armourLevel + 1);
+ }
+
+ public long getTimeEstimateForNextSword(Member member) {
+ int swordLevel = getBot().getSword(member).getLevel();
+ return getTimeEstimate(member, swordLevel + 1);
+ }
+
+ public Map<MineshaftItem, Long> getSwordUpgradeCost(Member member) {
+ int level = getBot().getSword(member).getLevel();
+
+ switch ((int) level) {
+ case 0:
+ return Collections.singletonMap(MineshaftItem.COPPER, 800l);
+ case 1:
+ return Collections.singletonMap(MineshaftItem.IRON, 1600l);
+ case 2:
+ return Collections.singletonMap(MineshaftItem.GOLD, 1600l);
+ case 3:
+ return Collections.singletonMap(MineshaftItem.DIAMOND, 1600l);
+ case 4:
+ return Collections.singletonMap(MineshaftItem.NETHERITE, 1600l);
+ }
+
+ return Collections.emptyMap();
+ }
+
+ public Map<MineshaftItem, Long> getArmourUpgradeCost(Member member) {
+ int level = getBot().getArmour(member).getLevel();
+
+ switch ((int) level) {
+ case 0:
+ return Collections.singletonMap(MineshaftItem.COPPER, 600l);
+ case 1:
+ return Collections.singletonMap(MineshaftItem.IRON, 1200l);
+ case 2:
+ return Collections.singletonMap(MineshaftItem.GOLD, 1200l);
+ case 3:
+ return Collections.singletonMap(MineshaftItem.DIAMOND, 1200l);
+ case 4:
+ return Collections.singletonMap(MineshaftItem.NETHERITE, 1200l);
+ }
+
+ return Collections.emptyMap();
+ }
+
+ public boolean isReady(Member member) {
+ if (!isWorking(member))
+ return false;
+
+ return getQuantity(member) < 0;
+ }
+
+ public void incrementQuestions(Member member) {
+ questionsStat.increment(member, 1);
+ }
+
+ public void resetQuestions(Member member) {
+ questionsStat.set(member, 0);
+ }
+
+ public long getQuestions(Member member) {
+ return questionsStat.get(member);
+ }
+
+ public String getWorkingString(Member member) {
+ long questions = getQuestions(member);
+ StringBuilder b = new StringBuilder();
+
+ long forges = getValidForgeCount(member);
+ if (forges > 1)
+ b.append("We are busy working on your ");
+ else
+ b.append("I am busy working on your ");
+
+ b.append(getWorkingName(member));
+ b.append(".\n");
+
+ if (questions < 1)
+ return b.toString();
+
+ if (questions == 1)
+ b.append("Please do not disturb me. ");
+
+ if (questions == 2)
+ b.append("Go away I'm busy. ");
+
+ if (questions == 3)
+ b.append("Leave me alone, let me work in peace... ");
+
+ if (questions == 4)
+ b.append("Stop bugging me. ");
+
+ if (questions == 5)
+ b.append("Fine, ");
+
+ if (questions >= 5) {
+ double progress = getProgress(member);
+ b.append("I am about " + + Math.round(100*progress) + "** of the way to finishing.\n");
+ }
+
+ if (questions == 6)
+ b.append("Happy? Now leave me alone. ");
+
+ if (questions == 7)
+ b.append("Is there anything more you want?");
+
+ if (questions == 8)
+ b.append("Thats the best I can give you ");
+
+ if (questions == 9)
+ b.append("You want a time estimate? If you keep bugging me I will never finish");
+
+ if (questions == 10)
+ b.append("Seriously, leave me alone! ");
+
+ if (questions == 11)
+ b.append("I have had it with you...");
+
+ if (questions >= 12)
+ b.append("It will be finished in *about* `" + PeelingUtils.formatTime(getTimeEstimateRemaining(member)) + "`\n");
+
+ if (questions == 12)
+ b.append("Happy now?");
+
+ if (questions == 13)
+ b.append("Is there anything else you want?");
+
+ if (questions == 14)
+ b.append("I can't give you any more info than that sorry...");
+
+ if (questions == 15)
+ b.append("Seriously that is all I know");
+
+ if (questions == 16)
+ b.append("If you keep asking then I won't ever finish");
+
+ if (questions == 17)
+ b.append("That is the best I have, sorry");
+
+ if (questions == 18)
+ b.append("Please be patient! ");
+
+ if (questions >= 19)
+ b.append("Please come back later! ");
+
+ if (questions == 50)
+ b.append("You sure are impatient aren't you?");
+
+ if (questions == 100)
+ b.append("This is the 100th time you've asked... I'm sure you are proud of yourself");
+
+ if (questions >= 500)
+ return "You have asked me too many times. No more updates sorry.";
+
+ return b.toString();
+
+ }
+
+
+}
diff --git a/src/main/java/net/uomc/mineshaft/blacksmith/BlacksmithCommand.java b/src/main/java/net/uomc/mineshaft/blacksmith/BlacksmithCommand.java
new file mode 100644
index 0000000..db57d55
--- /dev/null
+++ b/src/main/java/net/uomc/mineshaft/blacksmith/BlacksmithCommand.java
@@ -0,0 +1,151 @@
+package net.uomc.mineshaft.blacksmith;
+
+
+import java.awt.Color;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Stream;
+
+import com.mouldycheerio.dbot.CustomBot;
+import com.mouldycheerio.dbot.commands.CommandDetails;
+import com.mouldycheerio.dbot.commands.CommandFail;
+import com.mouldycheerio.dbot.commands.DetailedCommand;
+import com.mouldycheerio.dbot.util.PeelingUtils;
+
+import net.dv8tion.jda.api.EmbedBuilder;
+import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
+import net.uomc.mineshaft.Mineshaft;
+import net.uomc.mineshaft.MineshaftItem;
+
+public class BlacksmithCommand extends DetailedCommand {
+
+ private static final Color COMMAND_COLOUR = PeelingUtils.hex2Rgb("#252525");
+ private static final String COMMAND_TITLE = "Blacksmith";
+ private static final String COMMAND_IMAGE = "https://minecraft.wiki/images/Plains_Armorer.png?0dee1";
+
+ Mineshaft bot;
+ Blacksmith blacksmith;
+
+ public BlacksmithCommand(Mineshaft bot) {
+ setCommandDetails(CommandDetails.from("blacksmith", "upgrade your tools", "blacksmith upgrade"));
+ this.bot = bot;
+
+ blacksmith = new Blacksmith(bot);
+
+ bot.getCommandController().addCommand("upgrade", (e, b, args) -> {
+ // allow also upgrading pickaxe
+ if (Arrays.stream(args).filter(a -> a.equalsIgnoreCase("pick") || a.equalsIgnoreCase("pickaxe")).findFirst().isPresent()) {
+ bot.getCommandController().getCommand("pickaxe").execute(e, bot, new String[]{"upgrade"});
+ return;
+ }
+
+ execute(e, bot, Stream.concat(Stream.of("upgrade"), Arrays.stream(args)).toArray(String[]::new));
+ });
+ }
+
+ @Override
+ public void execute(MessageReceivedEvent e, CustomBot b, String[] args) throws CommandFail {
+ Member m = e.getMember();
+ List<String> argList = Arrays.asList(args);
+
+ long blacksmiths = bot.getItem(m, MineshaftItem.BLACKSMITH);
+
+ if (blacksmiths < 1) {
+ b.sendErrorMessage(e, ":x: You need to have at least **"
+ + bot.getItem(MineshaftItem.BLACKSMITH).prettyValue(1)
+ + "** to use this!");
+ return;
+ }
+
+ long forges = bot.getItem(m, MineshaftItem.FORGE);
+
+ EmbedBuilder em = new EmbedBuilder();
+ em.setTitle(COMMAND_TITLE);
+ em.setThumbnail(COMMAND_IMAGE);
+ em.setColor(COMMAND_COLOUR);
+
+ blacksmith.update(m);
+
+ if (blacksmith.isWorking(m)) {
+ if (blacksmith.isReady(m)) {
+ // do get new sword
+ return;
+ }
+
+ em.setDescription(blacksmith.getWorkingString(m));
+ blacksmith.incrementQuestions(m);
+ e.getMessage().replyEmbeds(em.build()).queue();
+ return;
+ }
+
+ if (args.length > 1 && "upgrade".equalsIgnoreCase(args[0])) {
+ if (forges < 1) {
+ em.setDescription(String.format("Sorry, I can't work without a forge %s!", bot.getItem(MineshaftItem.FORGE).getSymbol()));
+ return;
+ }
+
+ if (!upgrade(e, argList))
+ bot.sendErrorMessage(e, String.format(":x: Usage `%supgrade [sword|armour]`", bot.getPrefixManager().getPrefix(e.getGuild())));
+ return;
+ }
+
+
+ em.appendDescription(String.format("Hello, I am your blacksmith. I can upgrade your tools and armour for you `%supgrade [sword|armour]`\n\n",
+ bot.getPrefixManager().getPrefix(e.getGuild())
+ ));
+
+ String swordName = "You have a **" + bot.getSword(m).getName() + " Sword**";
+ Map<MineshaftItem, Long> swordUpgradeCost = blacksmith.getSwordUpgradeCost(m);
+
+ if (bot.getSword(m).getLevel() == 0) {
+ swordName = "**You have no sword**";
+ }
+
+ String armourName = "You have a **" + bot.getArmour(m).getName() + " Armour**";
+ Map<MineshaftItem, Long> armourUpgradeCost = blacksmith.getArmourUpgradeCost(m);
+
+ if (bot.getArmour(m).getLevel() == 0) {
+ armourName = "**You have no armour**";
+ }
+
+ em.appendDescription(String.format("%s\n", swordName));
+ if (blacksmith.canUpgradeSword(m))
+ em.appendDescription(String.format("Upgrade to **%s** for **%s**\n",
+ blacksmith.getNextSwordName(m),
+ String.join(",", bot.createItemList(swordUpgradeCost).split("\n"))));
+
+ em.appendDescription("\n");
+
+ em.appendDescription(String.format("**%s**\n", armourName));
+ if (blacksmith.canUpgradeArmour(m))
+ em.appendDescription(String.format("Upgrade to **%s** for **%s**\n",
+ blacksmith.getNextArmourName(m),
+ String.join(",", bot.createItemList(armourUpgradeCost).split("\n"))));
+
+ em.appendDescription("\n");
+
+ if (blacksmiths > 1) {
+ long forgeCount = blacksmith.getValidForgeCount(m);
+ String total = bot.prettyValue(MineshaftItem.BLACKSMITH, blacksmiths);
+ if (forgeCount < blacksmiths) {
+ em.appendDescription("**" + forgeCount + "/" + total + "** are able to work.\n");
+ em.appendDescription("Get more " + bot.getItem(MineshaftItem.FORGE).getSymbol() + " so they can work!");
+ } else {
+ em.appendDescription("Your **" + total + "** are all able to work!");
+ }
+ } else if (blacksmiths == 1) {
+ em.appendDescription("I am currently working alone. Hire more **" + bot.getItem(MineshaftItem.BLACKSMITH).getSymbol() + "** to speed up progress!");
+ } else {
+ em.appendDescription("I need a " + bot.getItem(MineshaftItem.FORGE).getSymbol() + " so I can get to work!");
+ }
+
+ e.getMessage().replyEmbeds(em.build()).queue();
+
+ }
+
+ private boolean upgrade(MessageReceivedEvent e, List<String> argList) {
+ throw new UnsupportedOperationException("Unimplemented method 'upgrade'");
+ }
+}
diff --git a/src/main/java/net/uomc/mineshaft/blacksmith/Map.java b/src/main/java/net/uomc/mineshaft/blacksmith/Map.java
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/main/java/net/uomc/mineshaft/blacksmith/Map.java
diff --git a/src/main/java/net/uomc/mineshaft/blacksmith/Pickaxe.java b/src/main/java/net/uomc/mineshaft/blacksmith/Pickaxe.java
new file mode 100644
index 0000000..ffe18d5
--- /dev/null
+++ b/src/main/java/net/uomc/mineshaft/blacksmith/Pickaxe.java
@@ -0,0 +1,211 @@
+package net.uomc.mineshaft.blacksmith;
+
+import java.sql.SQLException;
+import java.util.Collections;
+
+import com.mouldycheerio.dbot.util.DatabaseUtils;
+
+import net.dv8tion.jda.api.entities.Member;
+import net.uomc.mineshaft.Mineshaft;
+import net.uomc.mineshaft.SavedStat;
+
+public class Pickaxe extends Tool {
+
+ public static final int MAX_PICKAXE_LEVEL = 5;
+
+ public static final String LEVEL_TABLE = "pickaxe_level";
+ public static final String FORTUNE_TABLE = "pickaxe_ench_fortune";
+ public static final String EFFICIENCY_TABLE = "pickaxe_ench_efficiency";
+
+ private SavedStat levelStat;
+ private SavedStat fortuneStat;
+ private SavedStat efficiencyStat;
+
+ public Pickaxe(Mineshaft mineshaft, Member member) {
+ super(mineshaft, member, "pickaxe");
+ initStats();
+ }
+
+ private void initStats() {
+ System.out.println("initing stats");
+ try {
+ upgradeTableVersion();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+
+ levelStat = bot.getPlayerStats().getStat(LEVEL_TABLE);
+ fortuneStat = bot.getPlayerStats().getStat(FORTUNE_TABLE);
+ efficiencyStat = bot.getPlayerStats().getStat(EFFICIENCY_TABLE);
+ }
+
+ private void upgradeTableVersion() throws SQLException {
+ String dbPath = bot.getPlayerStats().getDbPath();
+ String oldLevelTable = "levels";
+ System.out.println("checking if table " + oldLevelTable + " exists...");
+ if (DatabaseUtils.tableExists(dbPath, oldLevelTable)) {
+ System.out.println("it does!");
+ if (DatabaseUtils.tableExists(dbPath, LEVEL_TABLE)) {
+ DatabaseUtils.deleteTable(dbPath, LEVEL_TABLE);
+ }
+
+ DatabaseUtils.renameTable(dbPath, oldLevelTable, LEVEL_TABLE);
+ }
+
+ String oldFortuneTable = "ench_fortune";
+ if (DatabaseUtils.tableExists(dbPath, oldFortuneTable)) {
+ if (DatabaseUtils.tableExists(dbPath, FORTUNE_TABLE)) {
+ DatabaseUtils.deleteTable(dbPath, FORTUNE_TABLE);
+ }
+
+ DatabaseUtils.renameTable(dbPath, oldFortuneTable, FORTUNE_TABLE);
+ }
+
+ String oldEfficiencyTable = "ench_efficiency";
+ if (DatabaseUtils.tableExists(dbPath, oldEfficiencyTable)) {
+ if (DatabaseUtils.tableExists(dbPath, EFFICIENCY_TABLE)) {
+ DatabaseUtils.deleteTable(dbPath, EFFICIENCY_TABLE);
+ }
+
+ DatabaseUtils.renameTable(dbPath, oldEfficiencyTable, EFFICIENCY_TABLE);
+ }
+ }
+
+
+ public void setLevel(long value) {
+ levelStat.set(member, value);
+ }
+
+ public int getLevel() {
+ return (int) levelStat.get(member);
+ }
+
+ public void setEfficiency(int value) {
+ efficiencyStat.set(member, value);
+ }
+
+ public int getEfficiency() {
+ return (int) efficiencyStat.get(member);
+ }
+
+ public void setFortune(int value) {
+ efficiencyStat.set(member, value);
+ }
+
+ public int getFortune() {
+ return (int) fortuneStat.get(member);
+ }
+
+ public boolean isEnchanted() {
+ long fortune = getFortune();
+ long eff = getEfficiency();
+ return fortune+eff > 0;
+ }
+
+ public String getName() {
+ long level = getLevel();
+ return pickaxeLevelToName(level);
+ }
+
+ public String getNextName() {
+ long level = getLevel() + 1;
+ if (level == getMaxLevel())
+ level = getMaxLevel();
+
+ return pickaxeLevelToName(level);
+ }
+
+ public static String pickaxeLevelToName(long level) {
+ switch ((int) level) {
+ case 0:
+ return "Stone";
+ case 1:
+ return "Copper";
+ case 2:
+ return "Iron";
+ case 3:
+ return "Gold";
+ case 4:
+ return "Diamond";
+ default:
+ return "Netherite";
+ }
+ }
+
+ public String getImage() {
+ long level = getLevel();
+ switch ((int) level) {
+ case 0:
+ return isEnchanted() ?
+ "https://minecraft.wiki/images/Enchanted_Stone_Pickaxe.gif"
+ : "https://minecraft.wiki/images/Stone_Pickaxe_JE2_BE2.png";
+ case 1:
+ return isEnchanted() ?
+ "https://minecraft.wiki/images/Enchanted_Copper_Pickaxe.webp"
+ : "https://minecraft.wiki/images/Copper_Pickaxe_JE1_BE1.png";
+ case 2:
+ return isEnchanted() ?
+ "https://minecraft.wiki/images/Enchanted_Iron_Pickaxe.gif"
+ : "https://minecraft.wiki/images/Iron_Pickaxe_JE3_BE2.png";
+ case 3:
+ return isEnchanted() ?
+ "https://minecraft.wiki/images/Enchanted_Golden_Pickaxe.gif"
+ : "https://minecraft.wiki/images/Golden_Pickaxe_JE4_BE3.png";
+ case 4:
+ return isEnchanted() ?
+ "https://minecraft.wiki/images/Enchanted_Diamond_Pickaxe.gif"
+ : "https://minecraft.wiki/images/Diamond_Pickaxe_JE3_BE3.png";
+ default:
+ return isEnchanted() ?
+ "https://minecraft.wiki/images/Netherite_Pickaxe_JE3.png"
+ : "https://minecraft.wiki/images/Enchanted_Netherite_Pickaxe.gif";
+ }
+ }
+
+ public int getMaxLevel() {
+ return MAX_PICKAXE_LEVEL;
+ }
+
+ public int incrementFortune() {
+ fortuneStat.increment(member, 1);
+ return (int) getFortune();
+ }
+
+ public int incrementEfficiency() {
+ efficiencyStat.increment(member, 1);
+ return (int) getEfficiency();
+ }
+
+ public static String getRomanNumber(int number) {
+ return String.join("", Collections.nCopies(number, "I"))
+ .replace("IIIII", "V")
+ .replace("IIII", "IV")
+ .replace("VV", "X")
+ .replace("VIV", "IX")
+ .replace("XXXXX", "L")
+ .replace("XXXX", "XL")
+ .replace("LL", "C")
+ .replace("LXL", "XC")
+ .replace("CCCCC", "D")
+ .replace("CCCC", "CD")
+ .replace("DD", "M")
+ .replace("DCD", "CM");
+ }
+
+ public String getEnchantmentString() {
+ int fortune = getFortune();
+ int efficiency = getEfficiency();
+ String curr = "";
+ if (fortune > 0 || efficiency > 0) {
+ curr = "is enchanted with ";
+ if (fortune > 0)
+ curr += "**Fortune " + Pickaxe.getRomanNumber(fortune) + "** ";
+ if (efficiency > 0)
+ curr += "**Efficiency " + Pickaxe.getRomanNumber(efficiency) + "** ";
+ } else {
+ curr = "has no enchantments";
+ }
+ return curr;
+ }
+
+}
diff --git a/src/main/java/net/uomc/mineshaft/blacksmith/Sword.java b/src/main/java/net/uomc/mineshaft/blacksmith/Sword.java
new file mode 100644
index 0000000..aa3fcea
--- /dev/null
+++ b/src/main/java/net/uomc/mineshaft/blacksmith/Sword.java
@@ -0,0 +1,77 @@
+package net.uomc.mineshaft.blacksmith;
+
+import net.dv8tion.jda.api.entities.Member;
+import net.uomc.mineshaft.Mineshaft;
+
+public class Sword extends Tool {
+ public static final int MAX_SWORD_LEVEL = 5;
+
+ public Sword(Mineshaft mineshaft, Member member) {
+ super(mineshaft, member, "sword");
+ }
+
+ public String getName() {
+ return swordLevelToName(getLevel());
+ }
+
+ public String getEmoji() {
+ // TODO add if enchanted
+ return swordToEmoji(getLevel());
+ }
+
+ public static String swordToEmoji(int level) {
+ switch ((int) level) {
+ case 0:
+ return "";
+ case 1:
+ return "<:copper_sword:1432879763193856060>";
+ case 2:
+ return "<:iron_sword:1432879761268412446>";
+ case 3:
+ return "<:gold_sword:1432879759385432155>";
+ case 4:
+ return "<:diamond_sword:1432879757065850941>";
+ default:
+ return "<:netherite_sword:1432879754712711278>";
+ }
+ }
+
+ public static String swordLevelToName(int level) {
+ switch ((int) level) {
+ case 0:
+ return "None";
+ case 1:
+ return "Copper";
+ case 2:
+ return "Iron";
+ case 3:
+ return "Gold";
+ case 4:
+ return "Diamond";
+ default:
+ return "Netherite";
+ }
+ }
+
+ public int getMaxLevel() {
+ return MAX_SWORD_LEVEL;
+ }
+
+ public long getDamageBonus() {
+ switch ((int) getLevel()) {
+ case 0: // "None";
+ return 0;
+ case 1: // "Copper";
+ return 2;
+ case 2: // "Iron";
+ return 4;
+ case 3: // "Gold";
+ return 6;
+ case 4: // "Diamond";
+ return 8;
+ default: // "Netherite";
+ return 10;
+ }
+ }
+
+}
diff --git a/src/main/java/net/uomc/mineshaft/blacksmith/Tool.java b/src/main/java/net/uomc/mineshaft/blacksmith/Tool.java
new file mode 100644
index 0000000..0a154e3
--- /dev/null
+++ b/src/main/java/net/uomc/mineshaft/blacksmith/Tool.java
@@ -0,0 +1,33 @@
+package net.uomc.mineshaft.blacksmith;
+
+import net.dv8tion.jda.api.entities.Member;
+import net.uomc.mineshaft.Mineshaft;
+import net.uomc.mineshaft.SavedStat;
+
+public class Tool {
+ Mineshaft bot;
+ Member member;
+
+ SavedStat levelStat;
+ String name;
+
+ public Tool(Mineshaft mineshaft, Member member, String name) {
+ this.name = name;
+ this.bot = mineshaft;
+ this.member = member;
+ initStats();
+ }
+
+ private void initStats() {
+ levelStat = bot.getPlayerStats().getStat(name + "_level");
+ }
+
+ public int getLevel() {
+ return (int) levelStat.get(member);
+ }
+
+ public void setLevel(int level) {
+ levelStat.set(member, level);
+ }
+
+}
diff --git a/src/main/java/net/uomc/mineshaft/blacksmith/Tools.java b/src/main/java/net/uomc/mineshaft/blacksmith/Tools.java
new file mode 100644
index 0000000..7727aca
--- /dev/null
+++ b/src/main/java/net/uomc/mineshaft/blacksmith/Tools.java
@@ -0,0 +1,48 @@
+package net.uomc.mineshaft.blacksmith;
+
+import java.util.HashMap;
+import java.util.Map;
+import net.dv8tion.jda.api.entities.Member;
+import net.uomc.mineshaft.Mineshaft;
+
+public class Tools {
+ private Mineshaft bot;
+
+ private Map<Member, Pickaxe> pickaxes;
+ private Map<Member, Armour> armours;
+ private Map<Member, Sword> swords;
+
+ public Tools(Mineshaft mineshaft) {
+ this.bot = mineshaft;
+ pickaxes = new HashMap<Member, Pickaxe>();
+ swords = new HashMap<Member, Sword>();
+ armours = new HashMap<Member, Armour>();
+ }
+
+ public Pickaxe getPickaxe(Member member) {
+ if (!pickaxes.containsKey(member)) {
+ Pickaxe pick = new Pickaxe(bot, member);
+ pickaxes.put(member, pick);
+ }
+
+ return pickaxes.get(member);
+ }
+
+ public Armour getArmour(Member member) {
+ if (!armours.containsKey(member)) {
+ Armour armour = new Armour(bot, member);
+ armours.put(member, armour);
+ }
+
+ return armours.get(member);
+ }
+ public Sword getSword(Member member) {
+ if (!swords.containsKey(member)) {
+ Sword sword = new Sword(bot, member);
+ swords.put(member, sword);
+ }
+
+ return swords.get(member);
+ }
+
+}
diff --git a/src/main/java/net/uomc/mineshaft/crafting/Crafting.java b/src/main/java/net/uomc/mineshaft/crafting/Crafting.java
index 6e2f670..9b257a2 100644
--- a/src/main/java/net/uomc/mineshaft/crafting/Crafting.java
+++ b/src/main/java/net/uomc/mineshaft/crafting/Crafting.java
@@ -151,7 +151,7 @@ public class Crafting extends DetailedCommand {
return "**" + r.getPrettyName() + "**\n"
+ bot.createItemList(recipe.getIngredients(), "%s", ", ")
- + " -> "
+ + " 🡒 "
+ r.prettyValue(recipe.getQuantity());
}).collect(Collectors.joining("\n\n"));
}
diff --git a/src/main/java/net/uomc/mineshaft/farm/Campfire.java b/src/main/java/net/uomc/mineshaft/farm/Campfire.java
new file mode 100644
index 0000000..d7d25c7
--- /dev/null
+++ b/src/main/java/net/uomc/mineshaft/farm/Campfire.java
@@ -0,0 +1,24 @@
+package net.uomc.mineshaft.farm;
+
+import net.uomc.mineshaft.Mineshaft;
+import net.uomc.mineshaft.MineshaftItem;
+
+class Campfire extends Farm {
+
+ private MineshaftItem cookedItem;
+ private long cookingTime;
+
+ public Campfire(Mineshaft bot, MineshaftItem item, MineshaftItem cookedItem, long cookingTime) {
+ super(bot, item);
+ this.cookedItem = cookedItem;
+ this.cookingTime = cookingTime;
+ }
+
+ public MineshaftItem getCookedItem() {
+ return cookedItem;
+ }
+
+ public long getCookingTime() {
+ return cookingTime;
+ }
+}
diff --git a/src/main/java/net/uomc/mineshaft/farm/CampfireCommand.java b/src/main/java/net/uomc/mineshaft/farm/CampfireCommand.java
new file mode 100644
index 0000000..e3138dc
--- /dev/null
+++ b/src/main/java/net/uomc/mineshaft/farm/CampfireCommand.java
@@ -0,0 +1,258 @@
+package net.uomc.mineshaft.farm;
+
+import static net.uomc.mineshaft.PlayerHealths.HP_EMOJI;
+
+import java.awt.Color;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.stream.Stream;
+
+import com.mouldycheerio.dbot.CustomBot;
+import com.mouldycheerio.dbot.commands.CommandDetails;
+import com.mouldycheerio.dbot.commands.CommandFail;
+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.Member;
+import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
+import net.uomc.mineshaft.Mineshaft;
+import net.uomc.mineshaft.MineshaftItem;
+
+public class CampfireCommand extends DetailedCommand {
+
+ private static final Color COMMAND_COLOUR = PeelingUtils.hex2Rgb("#a45802");
+ private static final String COMMAND_TITLE = "Campfire";
+ private static final String COMMAND_IMAGE = "https://minecraft.wiki/images/Campfire_%28S%29_JE2_BE2.gif";
+ public static final int ITEMS_PER_CAMPFIRE = 4;
+ public static final long POTATO_COOKING_TIME = 1000l * 40l;
+ public static final long FISH_COOKING_TIME = 1000l * 90l;
+
+ Mineshaft bot;
+ List<Campfire> farms;
+
+ public CampfireCommand(Mineshaft bot) {
+ setCommandDetails(CommandDetails.from("campfire", "cook your food", "farm"));
+ this.bot = bot;
+
+ farms = new ArrayList<>();
+ farms.add(new Campfire(bot, MineshaftItem.FISH, MineshaftItem.COOKED_FISH, FISH_COOKING_TIME));
+ farms.add(new Campfire(bot, MineshaftItem.POTATO, MineshaftItem.BAKED_POTATO, POTATO_COOKING_TIME));
+
+ bot.getCommandController().addCommand("cook", (e, b, args) -> {
+ execute(e, bot, Stream.concat(Stream.of("cook"), Arrays.stream(args)).toArray(String[]::new));
+ });
+ }
+
+ @Override
+ public void execute(MessageReceivedEvent e, CustomBot b, String[] args) throws CommandFail {
+ Member m = e.getMember();
+ List<String> argList = Arrays.asList(args);
+
+ long campfires = bot.getItem(m, MineshaftItem.CAMPFIRE);
+
+ if (campfires < 1) {
+ b.sendErrorMessage(e, ":x: You need to have at least **"
+ + bot.getItem(MineshaftItem.CAMPFIRE).prettyValue(1)
+ + "** to use this!");
+ return;
+ }
+
+ update(m);
+
+ if (args.length > 1 && "cook".equalsIgnoreCase(args[0])) {
+ if (!cook(e, argList))
+ bot.sendErrorMessage(e, String.format(":x: Usage `%scook [potato|fish] [amount] `", bot.getPrefixManager().getPrefix(e.getGuild())));
+ return;
+ }
+
+ StringBuilder description = new StringBuilder();
+ description.append(String.format("This is your campfire. You currently have %s\nUse `%scook [potato|fish] [amount]` to cook your food.\n\n",
+ bot.prettyValue(MineshaftItem.CAMPFIRE, campfires),
+ bot.getPrefixManager().getPrefix(e.getGuild())
+ ));
+
+ Map<MineshaftItem, Long> award = new HashMap<>();
+
+ List<String> cooking = new ArrayList<>();
+ AtomicLong waitingAmount = new AtomicLong();
+
+ // remove items if there are too many items for the num of campfires
+ //
+ long already = farms.stream().mapToLong(f -> f.getPlanted(m) + f.getQuantity(m)).sum();
+ if (already > campfires * ITEMS_PER_CAMPFIRE) {
+ AtomicLong toRemove = new AtomicLong(already - (campfires * ITEMS_PER_CAMPFIRE));
+ while (toRemove.get() > 0) {
+ long amountEach = toRemove.get();
+ farms.forEach(f -> {
+ long amount = amountEach;
+ if (amount == 0 || toRemove.get() < 1)
+ return; // we already removed enough
+
+
+ if (f.getQuantity(m) >= amount) {
+ // count the cooked as removed
+ toRemove.addAndGet(-f.getQuantity(m));
+ return;
+ }
+
+ if (f.getPlanted(m) < amount) {
+ amount = f.getPlanted(m);
+
+ }
+ // otherwise remove from planted
+ toRemove.addAndGet(-amount);
+ f.setPlanted(m, f.getPlanted(m) - amount);
+ award.put(f.getItem(), amount);
+ });
+ }
+ }
+
+ // add the cooked items to the award
+ //
+ farms.forEach(farm -> {
+ long cooked = farm.getQuantity(m);
+ long waiting = farm.getPlanted(m);
+
+ if (cooked > 0) {
+ award.put(farm.getCookedItem(), cooked);
+ farm.setQuantity(m, 0);
+ cooked = 0;
+ }
+
+ if (waiting < 1)
+ return;
+
+ cooking.add(String.format("%s%s", waiting, bot.getItem(farm.getItem()).getSymbol()));
+ waitingAmount.addAndGet(waiting);
+ });
+
+
+ if (waitingAmount.get() == 0) {
+ description.append("*You have nothing on your campfire*\n");
+ } else {
+ description.append("You are currently cooking: " + String.join(",", cooking) + "\n");
+ }
+
+ if (award.size() > 0) {
+ description.append("\n");
+ description.append(bot.createItemList(award, "+%s"));
+ }
+
+ EmbedBuilder em = new EmbedBuilder();
+ em.setTitle(COMMAND_TITLE);
+ em.setThumbnail(COMMAND_IMAGE);
+ em.setDescription(description);
+ em.setColor(COMMAND_COLOUR);
+
+ bot.addItems(m, award);
+
+ if (campfires <= 1) {
+ em.setFooter(EmojiParser.parseToUnicode(":bulb:") + "Get more campfires to cook more food at a time");
+ } else {
+ em.setFooter(EmojiParser.parseToUnicode(":bulb:") + String.format("Cooking food increases the amount of %s it gives when you %seat it.", "HP", bot.getPrefixManager().getPrefix(e.getGuild())));
+ }
+
+ e.getMessage().replyEmbeds(em.build()).queue();
+ }
+
+ public boolean cook(MessageReceivedEvent e, List<String> args) {
+ if (args.size() > 3)
+ return false;
+
+ Optional<String> resourceName = args.stream().filter(s -> !s.equalsIgnoreCase("all") && !s.equalsIgnoreCase("cook") && !PeelingUtils.isLong(s)).findFirst();
+ if (resourceName.isEmpty())
+ return false;
+
+ MineshaftItem item = MineshaftItem.valueOf(resourceName.get().toUpperCase());
+ if (item == null) {
+ bot.sendErrorMessage(e, ":x: Please provide a valid item!");
+ return true;
+ }
+
+ long campfires = bot.getItem(e.getMember(), MineshaftItem.CAMPFIRE);
+
+ long already = farms.stream().mapToLong(f -> f.getPlanted(e.getMember()) + f.getQuantity(e.getMember())).sum();
+
+ long q = 0;
+ Optional<String> all = args.stream().filter(s -> s.equals("all")).findFirst();
+ if (all.isEmpty()) {
+ Optional<Long> quantity = args.stream().filter(s -> PeelingUtils.isLong(s)).map(s -> Long.parseLong(s)).findFirst();
+ if (quantity.isEmpty())
+ return false;
+
+ q = Math.abs(quantity.get());
+ } else {
+ q = Math.min(bot.getItem(item).get(e.getMember()), (campfires * ITEMS_PER_CAMPFIRE) - already ) ;
+ }
+
+
+ if (already + q > campfires * ITEMS_PER_CAMPFIRE) {
+ bot.sendErrorMessage(e, String.format(":x: You can only have %s items cooking at the same time!", campfires * ITEMS_PER_CAMPFIRE));
+ return true;
+ }
+
+ Optional<Campfire> farm = farms.stream().filter(f -> f.getItem() == item).findFirst();
+ if (farm.isEmpty()) {
+ bot.sendErrorMessage(e, ":x: This item cannot be cooked");
+ return true;
+ }
+
+ if (q > bot.getItem(item).get(e.getMember())) {
+ bot.sendErrorMessage(e, ":x: You dont have enough " + bot.getItem(item).getSymbol());
+ return true;
+ }
+
+ if (farm.get().getPlanted(e.getMember()) == 0) {
+ farm.get().setNextUpdate(e.getMember(), System.currentTimeMillis() + farm.get().getCookingTime());
+ }
+
+ bot.removeItem(e.getMember(), item, q);
+ farm.get().setPlanted(e.getMember(), farm.get().getPlanted(e.getMember()) + q);
+
+ bot.sendSuccessMessage(e, String.format("You put %s on your campfire%s! Come back later when they have finished cooking", bot.getItem(item).prettyValue(q), campfires > 1 ? "s" : ""));
+ return true;
+ }
+
+ public void update(Member m) {
+ farms.forEach(farm -> {
+ update(farm, m);
+ });
+ }
+
+ public void update(Campfire farm, Member m) {
+ long next = farm.getNextUpdate(m);
+ long now = System.currentTimeMillis();
+ if (next == 0) {
+ next = now;
+ }
+
+ if (next > now)
+ return;
+
+ long since = now - next;
+ long updates = since / farm.getCookingTime();
+ //System.out.printf("[farm %s] updates is %d\n", farm.getItem(), updates);
+
+ long campfires = bot.getItem(m, MineshaftItem.CAMPFIRE);
+
+ long planted = farm.getPlanted(m);
+
+ if (planted > 0) {
+ long toCook = (campfires * updates);
+ if (toCook > planted) {
+ toCook = planted;
+ }
+
+ farm.setQuantity(m, farm.getQuantity(m) + toCook);
+ farm.setPlanted(m, planted - toCook);
+ }
+ farm.setNextUpdate(m, farm.getNextUpdate(m) + farm.getCookingTime()*updates);
+ }
+}
diff --git a/src/main/java/net/uomc/mineshaft/farm/CompostCommand.java b/src/main/java/net/uomc/mineshaft/farm/CompostCommand.java
index 0da607d..ce5deea 100644
--- a/src/main/java/net/uomc/mineshaft/farm/CompostCommand.java
+++ b/src/main/java/net/uomc/mineshaft/farm/CompostCommand.java
@@ -73,7 +73,7 @@ public class CompostCommand extends CooldownCommand {
long itemAmount = getMaxCompostable(e.getMember(), composters, i);
long bonemealAmount = (long) (itemAmount / COMPOST_LEVEL);
- description.append(String.format("%s->%s\n", bot.getItem(i).prettyValue(itemAmount), bot.getItem(MineshaftItem.BONEMEAL).prettyValue(bonemealAmount)));
+ description.append(String.format("%s🡒%s\n", bot.getItem(i).prettyValue(itemAmount), bot.getItem(MineshaftItem.BONEMEAL).prettyValue(bonemealAmount)));
});
if (amount.get() == 0) {
@@ -120,7 +120,7 @@ public class CompostCommand extends CooldownCommand {
bot.addItem(e.getMember(), MineshaftItem.BONEMEAL, bonemealAmount);
String content = String.format(":white_check_mark: You turned %s into %s", bot.getItem(item).prettyValue(itemAmount), bot.getItem(MineshaftItem.BONEMEAL).prettyValue(bonemealAmount));
- if (bot.getPickaxes().getFarmLevel(e.getMember()) < 1) {
+ if (bot.getPlayerStats().getFarmLevel(e.getMember()) < 1) {
content += "\nUse your bonemeal to expand your `m!farm`";
}
bot.sendSuccessMessage(e, content);
diff --git a/src/main/java/net/uomc/mineshaft/farm/Farm.java b/src/main/java/net/uomc/mineshaft/farm/Farm.java
index d990216..5326df1 100644
--- a/src/main/java/net/uomc/mineshaft/farm/Farm.java
+++ b/src/main/java/net/uomc/mineshaft/farm/Farm.java
@@ -9,7 +9,7 @@ import net.dv8tion.jda.api.entities.Member;
import net.uomc.mineshaft.Mineshaft;
import net.uomc.mineshaft.MineshaftItem;
-class Farm{
+public class Farm {
private MineshaftItem item;
@@ -87,7 +87,7 @@ class Farm{
} catch (SQLException e) {
e.printStackTrace();
}
- return 0l;
+ return System.currentTimeMillis();
}
public void incrementPlanted(Member member, long d) {
@@ -103,6 +103,10 @@ class Farm{
return q;
}
+ public Mineshaft getBot() {
+ return bot;
+ }
+
public MineshaftItem getItem() {
return item;
}
diff --git a/src/main/java/net/uomc/mineshaft/farm/FarmCommand.java b/src/main/java/net/uomc/mineshaft/farm/FarmCommand.java
index 43b7576..bf700ab 100644
--- a/src/main/java/net/uomc/mineshaft/farm/FarmCommand.java
+++ b/src/main/java/net/uomc/mineshaft/farm/FarmCommand.java
@@ -11,6 +11,7 @@ import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.IntStream;
+import java.util.stream.Stream;
import com.mouldycheerio.dbot.CustomBot;
import com.mouldycheerio.dbot.commands.CommandDetails;
@@ -44,13 +45,23 @@ public class FarmCommand extends DetailedCommand {
farms.add(new Farm(bot, MineshaftItem.CANE));
farms.add(new Farm(bot, MineshaftItem.CARROT));
farms.add(new Farm(bot, MineshaftItem.POTATO));
+
+ bot.getCommandController().addCommand("plant", (e, b, args) -> {
+ execute(e, bot, Stream.concat(Stream.of("plant"), Arrays.stream(args)).toArray(String[]::new));
+ });
+ bot.getCommandController().addCommand("harvest", (e, b, args) -> {
+ execute(e, bot, Stream.concat(Stream.of("harvest"), Arrays.stream(args)).toArray(String[]::new));
+ });
+ bot.getCommandController().addCommand("expand", (e, b, args) -> {
+ execute(e, bot, Stream.concat(Stream.of("expand"), Arrays.stream(args)).toArray(String[]::new));
+ });
}
@Override
public void execute(MessageReceivedEvent e, CustomBot b, String[] args) throws CommandFail {
List<String> argList = Arrays.asList(args);
- if (bot.getPickaxes().isNether(e.getMember())) {
+ if (bot.getPlayerStats().isNether(e.getMember())) {
bot.sendErrorMessage(e, ":x: You cannot access your farm from the nether");
return;
}
@@ -72,7 +83,7 @@ public class FarmCommand extends DetailedCommand {
return;
}
- long farmLevel = bot.getPickaxes().getFarmLevel(e.getMember());
+ long farmLevel = bot.getPlayerStats().getFarmLevel(e.getMember());
StringBuilder description = new StringBuilder();
description.append(String.format("This is your farm.\nUse `%sfarm plant [carrot|potato|cane] [amount]` to plant\nUse `%sfarm harvest` to harvest your crops\nUse %s to expand your farm with `%sfarm expand`\n\n",
bot.getPrefixManager().getPrefix(e.getGuild()),
@@ -126,9 +137,9 @@ public class FarmCommand extends DetailedCommand {
}
bot.removeItem(e.getMember(), item, q);
- long farmLevel = bot.getPickaxes().getFarmLevel(e.getMember());
- bot.getPickaxes().setFarmLevel(e.getMember(), farmLevel + q);
- farmLevel = bot.getPickaxes().getFarmLevel(e.getMember());
+ long farmLevel = bot.getPlayerStats().getFarmLevel(e.getMember());
+ bot.getPlayerStats().setFarmLevel(e.getMember(), farmLevel + q);
+ farmLevel = bot.getPlayerStats().getFarmLevel(e.getMember());
bot.sendSuccessMessage(e, ":white_check_mark: You expanded your farm. Now it can hold " + farmLevel + " crops");
return true;
@@ -254,7 +265,7 @@ public class FarmCommand extends DetailedCommand {
}
public long plant(Farm farm, Member member, long amount) {
- long farmLevel = bot.getPickaxes().getFarmLevel(member);
+ long farmLevel = bot.getPlayerStats().getFarmLevel(member);
long totalPlanted = getTotalPlanted(member);
if (totalPlanted + amount > farmLevel) {
amount = farmLevel - totalPlanted;
diff --git a/src/main/java/net/uomc/mineshaft/farm/TradeCommand.java b/src/main/java/net/uomc/mineshaft/farm/TradeCommand.java
index f512afe..ad3a1be 100644
--- a/src/main/java/net/uomc/mineshaft/farm/TradeCommand.java
+++ b/src/main/java/net/uomc/mineshaft/farm/TradeCommand.java
@@ -45,12 +45,13 @@ public class TradeCommand extends CooldownCommand {
MineshaftItem.BOOK,
MineshaftItem.LAPIS,
MineshaftItem.COAL,
+ MineshaftItem.WOOL,
};
public static MineshaftItem[] buyingItems = {
MineshaftItem.CARROT,
MineshaftItem.CANE,
- MineshaftItem.POTATO
+ MineshaftItem.POTATO,
};
Mineshaft bot;
@@ -98,7 +99,7 @@ public class TradeCommand extends CooldownCommand {
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("**%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",