Fanny Posted February 3, 2024 Share Posted February 3, 2024 (edited) Never coded in Java before and first script! It's a really simple one, but hopefully somebody gets some use out of it Would really appreciate any feedback regards the code & methodology (but not planning to add features) *Note: membership ran out before I got widgets working, so its kind of a guess whether it works or not... Would appreciate widget help tips... It can be modified to just wait a period of time and then press 1 or something to bypass widgets (thats how I used it since they seem difficult to use) import java.util.List; import org.osbot.rs07.api.ui.Skill; import org.osbot.rs07.api.model.Item; import org.osbot.rs07.api.ui.RS2Widget; import org.osbot.rs07.script.Script; import org.osbot.rs07.script.ScriptManifest; import org.osbot.rs07.utility.ConditionalSleep; @ScriptManifest(author = "Fanny", info = "Fletches arrow shafts and makes headless arrows", name = "Fanny Shafter", version = 1.0, logo = "") public class FannyShafter extends Script { private long startTime; private int startLevel; private long startXp; private final String[] logTypes = {"Logs", "Oak logs", "Willow logs", "Maple logs", "Yew logs", "Magic logs"}; private final int[] levelRequirements = {1, 15, 30, 45, 60, 75}; private String logType; private long lastAnimationTime = 0; @Override public void onStart() { // onStart logic remains unchanged } @Override public int onLoop() throws InterruptedException { if (shouldFletch()) { fletchArrowShafts(); } else if (shouldBank()) { handleBanking(); } else { stop(); } return random(200, 300); // Wait time before the loop starts over } private void handleBanking() throws InterruptedException { // Enhanced banking logic considering both logs and knife if (!getBank().isOpen() && !getBank().open()) return; new ConditionalSleep(5000, 1000) { @Override public boolean condition() throws InterruptedException { return getBank().isOpen(); } }.sleep(); if (!getInventory().contains("Knife") && getBank().contains("Knife")) { getBank().withdraw("Knife", 1); } else if(!getBank().contains("Knife") && !getInventory().contains("Knife")){ stop(); } for (String log : logTypes) { if (getBank().contains(log) && getSkills().getStatic(Skill.FLETCHING) >= getLevelRequirement(log)) { getBank().withdrawAll(log); break; } } getBank().close(); } private boolean shouldBank() { // Check if player needs to bank return !hasRequiredItemsForFletching(); } private boolean shouldFletch() { // Check if player can fletch return hasRequiredItemsForFletching(); } private boolean hasRequiredItemsForFletching() { // Check if the inventory contains a knife and any of the log types if (!getInventory().contains("Knife")) { return false; } for (String log : logTypes) { if (getInventory().contains(log) && getSkills().getStatic(Skill.FLETCHING) >= getLevelRequirement(log)) { return true; } } return false; } private int getLevelRequirement(String logType) { // Return the level requirement for the given log type for (int i = 0; i < logTypes.length; i++) { if (logTypes[i].equals(logType)) { return levelRequirements[i]; } } return 0; // Default to 0 if log type not found } private void fletchArrowShafts() throws InterruptedException { // Check bank is closed, then proceed to check logs & fletch if (getBank().isOpen()) closeBank(); for (String log : logTypes) { if (getInventory().contains(log) && getSkills().getStatic(Skill.FLETCHING) >= getLevelRequirement(log)) { Item logToUse = getInventory().getItem(log); handleFletching(logToUse); break; } } } private void handleFletching(Item log) throws InterruptedException { // Check if log is not null if (log == null) { return; } boolean knifeUsedFirst = random(0, 2) == 0; // Randomly decide whether to use the knife or the log first if (knifeUsedFirst ? getInventory().interact("Use", "Knife") : log.interact("Use")) { new ConditionalSleep(2000, 500) { @Override public boolean condition() throws InterruptedException { return getInventory().isItemSelected(); } }.sleep(); sleep(random(50, 300)); } if (knifeUsedFirst ? log.interact("Use") : getInventory().interact("Use", "Knife")) { sleep(random(100,300)); } new ConditionalSleep(5000, 1000) { @Override public boolean condition() throws InterruptedException { return isFletchingWidgetOpen(); } }.sleep(); sleep(random(100, 800)); RS2Widget fletchingWidget = getFletchingWidget(); if (fletchingWidget != null) { if (random(0, 100) < 25) { fletchingWidget.interact("15 arrow shafts"); } else { getKeyboard().typeKey((char) 49); } } sleep(random(800,2500)); getMouse().moveOutsideScreen(); final long[] lastAnimated = {System.currentTimeMillis()}; new ConditionalSleep(25000) { // Wait up to 25 seconds @Override public boolean condition() throws InterruptedException { // Check if the player is animating if(!getInventory().contains(logType)) { return true; } else if (myPlayer().isAnimating()) { // Update lastAnimated if the player is still animating lastAnimated[0] = System.currentTimeMillis(); } // Return true if more than 5 seconds have elapsed since lastAnimated return (System.currentTimeMillis() - lastAnimated[0]) > 5000; } }.sleep(); // AFK returning to screen exponentialBackoffSleep(); } private void exponentialBackoffSleep() throws InterruptedException{ final int duration = random(1,3) * random(1,3) * random(1,3) * random(1, 3) * random(100, 300); sleep(duration); } private boolean isFletchingWidgetOpen(){ if(getFletchingWidget() != null){ return true; } return false; } private RS2Widget getFletchingWidget() { List<RS2Widget> allWidgets = getWidgets().getAll(); RS2Widget storedWidget = allWidgets.stream().filter(w -> w.getWidth() == 52 && w.getHeight() == 52 && w.getItemId() == 52).findFirst().orElse(null); return storedWidget; } private void closeBank() throws InterruptedException { // Logic to close the bank getBank().close(); new ConditionalSleep(3000, 1000) { @Override public boolean condition() throws InterruptedException { return !getBank().isOpen(); } }.sleep(); } } Edited February 3, 2024 by Fanny Quote Link to comment Share on other sites More sharing options...
Czar Posted February 3, 2024 Share Posted February 3, 2024 noice !! Quote Link to comment Share on other sites More sharing options...
Tom Posted February 3, 2024 Share Posted February 3, 2024 i like the name Quote Link to comment Share on other sites More sharing options...
yfoo Posted February 7, 2024 Share Posted February 7, 2024 (edited) Neat! What about adding an additional step to have headless arrowheads in inventory and use those as well? Regarding the make widget I think the root id is 270. Also you can use "1" hotkey instead of clicking the widget since arrowheads are always the 1st option from the left. Here is a example of how I get the widget then interact with it with spacebar. Same concept as "1" hotkey. Except spacebar repeats the last widget interaction used. https://github.com/YifanLi5/Bankstanding-Skiller/blob/cc8c13d063fd141125494fe3bf7643330d14a49d/src/Task/CombineItems.java#L86 Edited February 7, 2024 by yfoo Quote Link to comment Share on other sites More sharing options...
Fanny Posted February 7, 2024 Author Share Posted February 7, 2024 3 hours ago, yfoo said: Neat! What about adding an additional step to have headless arrowheads in inventory and use those as well? Regarding the make widget I think the root id is 270. Also you can use "1" hotkey instead of clicking the widget since arrowheads are always the 1st option from the left. Here is a example of how I get the widget then interact with it with spacebar. Same concept as "1" hotkey. Except spacebar repeats the last widget interaction used. https://github.com/YifanLi5/Bankstanding-Skiller/blob/cc8c13d063fd141125494fe3bf7643330d14a49d/src/Task/CombineItems.java#L86 Thanks a lot for the tips, when I get enough gold for membership again I'l ltry that! Really appreciate the link; that randomGaussian method is a good idea for sleeps! Although I feel like I would add a base 50ms just because reaction time? I was also not aware of a conditionalSleep2 method - what is the difference? Quote Link to comment Share on other sites More sharing options...
yfoo Posted February 8, 2024 Share Posted February 8, 2024 (edited) 15 hours ago, Fanny said: Thanks a lot for the tips, when I get enough gold for membership again I'l ltry that! Really appreciate the link; that randomGaussian method is a good idea for sleeps! Although I feel like I would add a base 50ms just because reaction time? I was also not aware of a conditionalSleep2 method - what is the difference? >I was also not aware of a conditionalSleep2 method - what is the difference? regular CS requires you to make an object to call sleep. CS2.sleep() is a static method. >randomGaussian method is a good idea for sleeps! Although I feel like I would add a base 50ms just because reaction time? That's the point actually, I was using it to delay menu interactions by a small amount, like a human would. ex:) sleep(randomGaussian(300, 100)); keyboard.pressKey(KeyEvent.VK_SPACE); ScriptPaint.setStatus("Spacebar-ing make widget"); result = ConditionalSleep2.sleep(2000, () -> { List<RS2Widget> widgets = new ArrayList<>(getWidgets().containingActions(270, CREATE_VERBS)); return widgets.isEmpty(); }); sleep(randomGaussian(300, 100)); keyboard.releaseKey(KeyEvent.VK_SPACE); In this block, I wanted to wait a moment after the make widget appears before interacting with it. Then wait again after spacebar-ing it before releasing it. Edited February 8, 2024 by yfoo Quote Link to comment Share on other sites More sharing options...