Fanny Posted February 3 Share Posted February 3 (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 by Fanny Quote Link to comment Share on other sites More sharing options...
Czar Posted February 3 Share Posted February 3 noice !! Quote Link to comment Share on other sites More sharing options...
Tom Posted February 3 Share Posted February 3 i like the name Quote Link to comment Share on other sites More sharing options...
yfoo Posted February 7 Share Posted February 7 (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 by yfoo Quote Link to comment Share on other sites More sharing options...
Fanny Posted February 7 Author Share Posted February 7 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 Share Posted February 8 (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 by yfoo Quote Link to comment Share on other sites More sharing options...