Pseudo Posted January 7, 2021 Share Posted January 7, 2021 (edited) Another release for everyone. Features: - Fletches headless arrows from level 1-20 fletching (Have approx 5k arrow shafts and feathers banked). - Fletches the best possible bow (short and long) for it's level, progressively, from Oak shortbows all the way to Magic longbows. - Stops if it detects we're out of the necessary supplies. (Have more than enough of each log required for the progression if you intend on leaving it run for a long time unmonitored). import com.epicbot.api.shared.APIContext; import com.epicbot.api.shared.GameType; import com.epicbot.api.shared.entity.ItemWidget; import com.epicbot.api.shared.entity.WidgetChild; import com.epicbot.api.shared.model.Skill; import com.epicbot.api.shared.script.LoopScript; import com.epicbot.api.shared.script.ScriptManifest; import com.epicbot.api.shared.util.details.Completable; import com.epicbot.api.shared.util.paint.frame.PaintFrame; import com.epicbot.api.shared.util.time.Time; import com.epicbot.api.shared.util.time.Timer; import java.awt.*; import java.awt.event.KeyEvent; @ScriptManifest(name = "Λ Progressive Fletcher", gameType = GameType.OS) public class LambdaProgressiveFletcher extends LoopScript { private final Timer runTimer = new Timer(0); private final Timer experienceTimer = new Timer(5000); private Timer idleTimer = null; private final double version = 0.1; private int experienceGained, startExperience = 0; private final PaintFrame paintFrame = new PaintFrame(); private String status = ""; @Override protected int loop() { if (getAPIContext().client().isLoggedIn()) { handleCalculations(); doTasks(); } return 50; } private enum Task { FLETCHING, BANKING; @Override public String toString() { return this.name().toLowerCase(); } } private void handleCalculations() { if (startExperience == 0) { startExperience = getAPIContext().skills().get(Skill.Skills.FLETCHING).getExperience(); } else { if (!experienceTimer.isRunning()) { experienceGained = getAPIContext().skills().get(Skill.Skills.FLETCHING).getExperience() - startExperience; experienceTimer.reset(); } } } private void doTasks() { status = getCurrentTask().toString(); switch (getCurrentTask()) { case FLETCHING: doFletching(); break; case BANKING: doBanking(); break; } } private void buildPaintTitle() { paintFrame.setTitle(getManifest().name() + " v" + version); paintFrame.setColumnValueSpacing(0); } private boolean isFletching() { if (!hasInputItems() || idleTimer == null || idleTimer.getElapsed() >= getRandomNumber(2500, 4000)) return false; if (getAPIContext().localPlayer().getAnimation() != -1) { idleTimer = new Timer(0); return true; } return true; } private boolean hasInputItems() { return getAPIContext().inventory().contains(getFletchingMethod().getItemsRequired()); } private void doBanking() { if (getAPIContext().bank().isOpen()) { if (hasRequiredItemsInInventoryOrBank()) { if (getAPIContext().inventory().getCount() > 27) { if (getAPIContext().bank().depositAllExcept("Knife")) { Time.sleep(1800, () -> getAPIContext().inventory().getCount() <= 27); } } else { if (getFletchingMethod().getOutputName().contains("arrow")) { withdrawItem(getFletchingMethod().getItemsRequired()[0], 0); withdrawItem(getFletchingMethod().getItemsRequired()[1], 0); } else { withdrawItem("Knife", 1); withdrawItem(getFletchingMethod().getItemsRequired()[0], 0); } } } else { stop("We don't have the required items!"); } } else { if (getAPIContext().bank().open()) { Time.sleep(2400, () -> getAPIContext().bank().isOpen()); } } } private boolean withdrawItem(String itemName, int amount) { if (!getAPIContext().inventory().contains(itemName)) { if (amount == 0) { getAPIContext().bank().withdrawAll(itemName); } else { getAPIContext().bank().withdraw(amount, itemName); } } return Time.sleep(1000, 2000, () -> hasItem(itemName)); } private boolean hasItem(String itemName) { return getAPIContext().inventory().contains(itemName); } private boolean itemExistsInInventoryOrBank(String item) { return getAPIContext().inventory().contains(item) || getAPIContext().bank().contains(item); } private boolean hasRequiredItemsInInventoryOrBank() { for (String item : getFletchingMethod().getItemsRequired()) { if (item != null) { if (!itemExistsInInventoryOrBank(item)) return false; } } return true; } private void doFletching() { if (!getAPIContext().bank().isOpen()) { if (!isFletching()) { if (isWidgetValid(getTargetWidget())) { getAPIContext().keyboard().sendKey(getWidgetOptionKeyboardKey()); idleTimer = new Timer(0); Time.sleep(1200, 2000, this::isFletching); } else { if (getFletchingMethod().getOutputName().contains("arrow")) { if (handleItem(getFletchingMethod().getItemsRequired()[0], null, 1200, () -> getAPIContext().inventory().isItemSelected())) { handleItem(getFletchingMethod().getItemsRequired()[1], null, 1200, () -> isWidgetValid(getTargetWidget())); } } else { if (handleItem("Knife", null, 1200, () -> getAPIContext().inventory().isItemSelected())) { handleItem(getFletchingMethod().itemsRequired[0], null, 1200, () -> isWidgetValid(getTargetWidget())); } } } } else { idleTimer.reset(); Time.sleep(50, 300); } } else { if (closeBank()) { Time.sleep(1800, () -> !getAPIContext().bank().isOpen()); } } } private boolean hasEscToCloseInterface() { return getAPIContext().vars().getVarbit(4681) == 1; } private boolean closeBank() { if (hasEscToCloseInterface() && getWidgetOptionKeyboardKey() != -1) { getAPIContext().keyboard().sendKey(KeyEvent.VK_ESCAPE); return true; } else return getAPIContext().bank().close(); } private boolean isWidgetValid(WidgetChild widgetChild) { return widgetChild != null && widgetChild.isVisible(); } private WidgetChild getTargetWidget() { return getAPIContext().widgets().get(getParentWidgetId()).find(i -> i != null && getWidgetPredicateString() != null && i.getName().contains(getWidgetPredicateString())); } private int getWidgetOptionKeyboardKey() { if (getWidgetPredicateString() == null) return -1; return getWidgetPredicateString().equals("shortbow") ? KeyEvent.VK_2 : getWidgetPredicateString().equals("longbow") ? KeyEvent.VK_3 : KeyEvent.VK_1; } private String getWidgetPredicateString() { String output = getFletchingMethod().getOutputName(); if (output != null) { if (output.contains("shortbow")) { return "shortbow"; } else if (output.contains("longbow")) { return "longbow"; } else { return "arrow"; } } return null; } private int getParentWidgetId() { return 270; } private Task getCurrentTask() { if (!hasItemsRequired()) { return Task.BANKING; } else return Task.FLETCHING; } private boolean hasItemsRequired() { return inventoryContainsAllOf(getFletchingMethod().getItemsRequired()); } private boolean handleItem(String itemName, String action, int timeOut, Completable condition) { ItemWidget itemWidget = getAPIContext().inventory().getItem(itemName); if (itemWidget == null) return false; if (action != null) { if (itemWidget.interact(action)) { return Time.sleep(timeOut, condition); } } else { if (itemWidget.click()) { return Time.sleep(timeOut, condition); } } return false; } private int getRandomNumber(int min, int max) { return (int) ((Math.random() * (max - min)) + min); } @Override public boolean onStart(String... strings) { System.out.println("Starting " + getManifest().name() + " v" + version); buildPaintTitle(); return true; } private boolean inventoryContainsAllOf(String[] items) { for (String item : items) { if (item != null) { if (!getAPIContext().inventory().contains(item)) { return false; } } } return true; } private String rsFormat(Integer number) { String[] suffix = new String[]{"K", "M", "B", "T"}; int size = (number != 0) ? (int) Math.log10(number) : 0; if (size >= 3) { while (size % 3 != 0) { size = size - 1; } } return (size >= 3) ? +(Math.round((number / Math.pow(10, size)) * 10) / 10d) + suffix[(size / 3) - 1] : +number + ""; } private int getHourlyRate(int i) { return (int) (i / (runTimer.getElapsed() / 3600000.0D)); } private String getExperienceGainedString() { return "Experience gained: " + rsFormat(experienceGained) + " (" + rsFormat(getHourlyRate(experienceGained)) + ")"; } private String getStatusString() { return modifyString(status); } private String modifyString(String string) { String input = string.replace("_", " "); return input.substring(0, 1).toUpperCase() + input.substring(1); } private final Font boldText = new Font(Font.SANS_SERIF, Font.BOLD, 12); @Override protected void onPaint(Graphics2D g2d, APIContext ctx) { if (getAPIContext().client().isLoggedIn()) { paintFrame.draw(g2d, 20, 30, getAPIContext()); g2d.setFont(boldText); g2d.setColor(Color.WHITE); g2d.drawString("Time running: " + runTimer.toElapsedString(), 20, 70); g2d.drawString("Status: " + getStatusString(), 20, 90); g2d.drawString(getExperienceGainedString(), 20, 110); g2d.drawString("Fletching method: " + getFletchingMethod().toString(), 20, 130); super.onPaint(g2d, ctx); } } private int getFletchingLevel() { return getAPIContext().skills().get(Skill.Skills.FLETCHING).getRealLevel(); } private Fletch getFletchingMethod() { for (Fletch fletch : Fletch.values()) { if (fletch.getRequiredLevel() <= getFletchingLevel() && fletch.getTargetLevel() > getFletchingLevel()) { return fletch; } } return Fletch.HEADLESS_ARROW; } private enum Fletch { HEADLESS_ARROW("Headless arrow", 1, 20, new String[]{"Feather", "Arrow shaft"}), OAK_SHORTBOW("Oak shortbow", 20, 25, new String[]{"Oak logs"}), OAK_LONGBOW("Oak longbow", 25, 35, new String[]{"Oak logs"}), WILLOW_SHORTBOW("Willow shortbow", 35, 40, new String[]{"Willow logs"}), WILLOW_LONGBOW("Willow longbow", 40, 50, new String[]{"Willow logs"}), MAPLE_SHORTBOW("Maple shortbow", 50, 55, new String[]{"Maple logs"}), MAPLE_LONGBOW("Maple longbow", 55, 65, new String[]{"Maple logs"}), YEW_SHORTBOW("Yew shortbow", 65, 70, new String[]{"Yew logs"}), YEW_LONGBOW("Yew longbow", 70, 80, new String[]{"Yew logs"}), MAGIC_SHORTBOW("Magic shortbow", 80, 85, new String[]{"Magic logs"}), MAGIC_LONGBOW("Magic longbow", 85, 100, new String[]{"Magic logs"}); private final int requiredLevel, targetLevel; private final String[] itemsRequired; private final String outputName; Fletch(String outputName, int requiredLevel, int targetLevel, String[] itemsRequired) { this.outputName = outputName; this.requiredLevel = requiredLevel; this.targetLevel = targetLevel; this.itemsRequired = itemsRequired; } public int getRequiredLevel() { return requiredLevel; } public String getOutputName() { return outputName; } public int getTargetLevel() { return targetLevel; } public String[] getItemsRequired() { return itemsRequired; } } } See this post for how to compile local scripts if you intend on using this. Edited January 7, 2021 by Pseudo 1 1 Quote Link to comment Share on other sites More sharing options...
smile Posted January 7, 2021 Share Posted January 7, 2021 but can it kill vorkath tho? Quote Link to comment Share on other sites More sharing options...
Pseudo Posted January 7, 2021 Author Share Posted January 7, 2021 Just now, smile said: but can it kill vorkath tho? Only on Wednesdays 😕 1 Quote Link to comment Share on other sites More sharing options...
smile Posted January 7, 2021 Share Posted January 7, 2021 Just now, Pseudo said: Only on Wednesdays 😕 what's it kill on fridays? Quote Link to comment Share on other sites More sharing options...
Sellout Posted January 7, 2021 Share Posted January 7, 2021 damn keep 'm coming 😮 1 Quote Link to comment Share on other sites More sharing options...
Pseudo Posted January 7, 2021 Author Share Posted January 7, 2021 Forgot to mention, if you wanted to stop progressing logs/bows at say, maple, then you can do so by just simply modifying the enum. Quote Link to comment Share on other sites More sharing options...
Global Moderators MansNoThot Posted January 7, 2021 Global Moderators Share Posted January 7, 2021 Ayyy. Killing it with the releases! Quote Link to comment Share on other sites More sharing options...
Global Moderators Euan Posted January 8, 2021 Global Moderators Share Posted January 8, 2021 Nice man, looks great! Quote Link to comment Share on other sites More sharing options...
Pseudo Posted January 11, 2021 Author Share Posted January 11, 2021 (edited) 1-50 without interruption: Edited January 11, 2021 by Pseudo Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.