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 = 240; // TODO fix this public static long MS_PER_UPDATE = 1000l * 60l; //public static long MS_PER_UPDATE = 1000l * 10l; private SavedStat questionsStat; public Blacksmith(Mineshaft bot) { super(bot, MineshaftItem.BLACKSMITH); questionsStat = getBot().getPlayerStats().getStat("blacksmith_questions"); } public int collect(Member member) { if (!isReady(member)) return 0; if (isSword(member)) return collectSword(member); return collectArmour(member); } public int collectSword(Member member) { int levelRaw = (int) getPlanted(member); getBot().getSword(member).setLevel(getWorkingLevel(member)); setPlanted(member, 0); setQuantity(member, 0); return levelRaw; } public int collectArmour(Member member) { int levelRaw = (int) getPlanted(member); getBot().getArmour(member).setLevel(getWorkingLevel(member)); setPlanted(member, 0); setQuantity(member, 0); return levelRaw; } public int upgradeArmour(Member member) { int armourLevel = getBot().getArmour(member).getLevel(); if (armourLevel >= Armour.MAX_ARMOUR_LEVEL) { return 0; } armourLevel += 1; setPlanted(member, -armourLevel); getBot().getArmour(member).setLevel(0); setQuantity(member, armourLevel * UPDATES_PER_LEVEL); setNextUpdate(member, System.currentTimeMillis() + MS_PER_UPDATE); return armourLevel; } public int upgradeSword(Member member) { int swordLevel = getBot().getSword(member).getLevel(); if (swordLevel >= Sword.MAX_SWORD_LEVEL) { return 0; } swordLevel += 1; setPlanted(member, swordLevel); getBot().getSword(member).setLevel(0); setQuantity(member, swordLevel * UPDATES_PER_LEVEL); setNextUpdate(member, System.currentTimeMillis() + MS_PER_UPDATE); return swordLevel; } 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)); int change = bd.sample(); setQuantity(member, getQuantity(member) - change); System.out.println("Doing update on " + member.getEffectiveName() + ", updates = " + updates + ", changed by -" + change); 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 (double) (max - Math.max(current, 0)) / (double) 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 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 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 && questions <= 510) return "You have asked me too many times. No more updates sorry."; if (questions == 511) return "Ok fine. Come back later and I will tell you"; return b.toString(); } }