hotpoket Posted June 12, 2020 Share Posted June 12, 2020 (edited) I started with scripting yesterday, and I was wondering if I could get some feedback on a script I made to see if there are some glaring errors / best practices that I could implement. The purpose of the script is to perform a herb run. I am aware that this script does not account for dead herbs. I think the biggest issues are the sleeps, and I implement the while(true) loops and I believe a conditional sleep could be used instead but I haven't been able to implement them. @ScriptManifest(author = "HotPoket", info = "My first script", name = "Herb Running", version = 0, logo = "") public class Main extends Script { private static Area camelotPatch = new Area(2810,3460,2820, 3470); private static Area mortPatch = new Area(3600, 3528, 3605, 3533); private static Area ardyPatch = new Area(2668,3376, 2672, 3372); private static Area falPatch = new Area(3055, 3313, 3060, 3308); private static Area camBank = new Area(2808, 3440, 2810, 3438); private static int ardyCloakCharges = 0; @Override public void onStart() throws InterruptedException { if (checkSupplies()) { moveToCamelot(); farmPatch(); moveToMort(); farmPatch(); moveToFal(); farmPatch(); moveToArdy(); farmPatch(); } else { log("Not enough supplies to perform a herb run"); stop(); } } @Override public int onLoop() throws InterruptedException { return random(200, 300); } @Override public void onExit() { log("Thanks for running my Tea Thiever!"); } @Override public void onPaint(Graphics2D g) { } private boolean checkSupplies() throws InterruptedException { if (!getInventory().contains("Rake")) { log("Rake not found"); return false; } if (!getInventory().contains("Seed dibber")) { log("Seed Dibber Not Found"); return false; } if (!getInventory().contains("Spade")) { log("Spade not found"); return false; } if (getInventory().getAmount("Law rune") < 3 || getInventory().getAmount("Water rune") < 3 && getInventory().getAmount("Air rune") < 8) { log("Teleport runes not found"); return false; } if (!getInventory().contains("Ectophial")){ log("Ectophial not found"); return false; } Item [] myItems = getInventory().getItems(); int seedAmount = 0; int compostAmount = 0; for (Item i : myItems) { if (i != null && i.getName().contains("seed")) { seedAmount = i.getAmount(); } if (i!= null && i.getName().contains("post") && !i.isNote()) { compostAmount = (int) getInventory().getAmount(i.getName()); } } if (seedAmount < 4) { log("Seeds not found -- Seed Amount: " + seedAmount); return false; } return true; } private void noteHerbs() throws InterruptedException { Item [] myItems = getInventory().getItems(); for (Item i : myItems) { if (i != null && !i.isNote() && i.getName().contains("Grimy")) { i.interact("Use"); sleep(2000); NPC tl = npcs.closest("Tool Leprechaun"); tl.interact("Use"); sleep(2000); break; } } } private void banking() throws InterruptedException { getBank().open(); long numBuckets = getInventory().getAmount("Bucket"); if (numBuckets > 0) { getBank().deposit("Bucket", (int) numBuckets); } long numCompost = getInventory().getAmount("Ultracompost"); if (numCompost > 0) { getBank().depositAll(21483); } getBank().withdraw(21483, 5); } private void moveToMort() throws InterruptedException { getInventory().getItem("Ectophial").interact("Empty"); sleep(5000); walking.webWalk(mortPatch); } private void moveToCamelot() throws InterruptedException { log("Let's get started!"); magic.castSpell(Spells.NormalSpells.CAMELOT_TELEPORT); sleep(5000); walking.webWalk(camBank); banking(); walking.webWalk(camelotPatch); } private void moveToArdy() throws InterruptedException { log("Moving to Ardy"); magic.castSpell(Spells.NormalSpells.ARDOUGNE_TELEPORT); sleep(5000); walking.webWalk(ardyPatch); } private void moveToFal() throws InterruptedException { log("Moving to Falador"); magic.castSpell(Spells.NormalSpells.FALADOR_TELEPORT); sleep(5000); walking.webWalk(falPatch); } private int whichPatch() { if (camelotPatch.contains(myPlayer())) { log("Player is in the CamelotPatch"); return 8151; } { if (mortPatch.contains(myPlayer())) { return 8153; } if (ardyPatch.contains(myPlayer())) { log("Player is in the Ardy Patch"); return 8152; } if (falPatch.contains(myPlayer())) { log("Player is in the Falador Patch"); return 8150; } } log("Player is not at a patch -- Closing Script"); stop(); return 0; } private void farmPatch() throws InterruptedException { sleep(6000); noteHerbs(); RS2Object patch = getObjects().closest(whichPatch()); if (patch != null) { log("Found patch"); while (true) { String [] availableActions = patch.getActions(); if (availableActions[0] != null && availableActions[0].contains("Rake")) { log("yes"); patch.interact("Rake"); sleep(10000); } else break; } while (true) { String [] availableActions = patch.getActions(); if (availableActions[0] != null && availableActions[0].contains("Pick")) { log("yes"); patch.interact("Pick"); sleep(10000); } else break; } getInventory().dropAll("Weeds"); sleep(2000); patch = getObjects().closest("Herb patch"); Item compost = getInventory().getItem("Ultracompost"); compost.interact("Use"); sleep(3000); patch.interact("Use"); sleep(3000); Item i = getInventory().getItem("Avantoe seed"); i.interact("Use"); sleep(3000); patch.interact("Use"); sleep(3000); noteHerbs(); } } } Edited June 12, 2020 by hotpoket Quote Link to comment Share on other sites More sharing options...
Protoprize Posted June 12, 2020 Share Posted June 12, 2020 4 hours ago, hotpoket said: I started with scripting yesterday, and I was wondering if I could get some feedback on a script I made to see if there are some glaring errors / best practices that I could implement. Nice first script! some tips though from personal experience: If you want to do the script the way you have done it, look into this: Having a condition check whether a process can be done could help if the script skips one of the functions/tasks you have created, also splitting up each task for small scripts makes them easier to manage And instead of static sleep times, use conditional sleep This just makes your script run better and seem more human like (not to be confused with antiban) There are a lot more things you can do but someone else could chip in at some point with more help! A lot of this stuff, you just learn from experience, but so far, you got the basic logic down 1 Quote Link to comment Share on other sites More sharing options...
Nbacon Posted June 12, 2020 Share Posted June 12, 2020 Hello HotPoket, I Think its good start. I like the script. As you make more bots your code will get better and you'll learn the Api. Things I see I thinks a bad pratic to do everthing is start. Things like gui , walk to a bank , step up classes and values should go here. A non looping structure. Duplicate code. Things that the api can do but you will learn as you make more bots. Example checkSupplies method. Error in the amount of runes needed I think you need 4 laws not 3. conditionsleep Like what Protoprize said. 1. will be fixed by 2. 2. The best bots in my opinion are ones that have if else tree that clearly defines were you are in script for something like framing it would be a little harder. But when you get that logic down the bots are bullet proof. They can be start and stoped any were in the script and finsh the task. I think the loop would start like if bot-has-items if !bot-near-patch || patch-has-herb move-to-next // you can find out were you are at in the scrpit by amount of runes buckets of compost left else farmpatch else get-items Example my post in with a flax spiner 3. See the code fixes I post.[tpAndMoveToArea] 4.See the code fixes I post. [ checkSupplies, noteHerbs] 5. Just something I saw Fixes I would make : package com.bacon.AIO.paint; import com.bacon.AIO.util.Sleep; import org.osbot.rs07.api.map.Area; import org.osbot.rs07.api.map.Position; import org.osbot.rs07.api.model.Item; import org.osbot.rs07.api.model.NPC; import org.osbot.rs07.api.model.RS2Object; import org.osbot.rs07.api.ui.MagicSpell; import org.osbot.rs07.api.ui.Spells; import org.osbot.rs07.script.Script; import org.osbot.rs07.script.ScriptManifest; import java.awt.*; @ScriptManifest(author = "HotPoket", info = "My first script", name = "Herb Running", version = 0, logo = "") public class Main extends Script { private static final Area camelotPatch = new Area(2810, 3460, 2820, 3470); private static final Area mortPatch = new Area(3600, 3528, 3605, 3533); private static final Area ardyPatch = new Area(2668, 3376, 2672, 3372); private static final Area falPatch = new Area(3055, 3313, 3060, 3308); private static final Area camBank = new Area(2808, 3440, 2810, 3438); @Override public void onStart() throws InterruptedException { gui maybe? } @Override public int onLoop() throws InterruptedException { /* if (checkSupplies()) { moveToCamelot(); farmPatch(); moveToMort(); farmPatch(); tpAndMoveToArea(Spells.NormalSpells.FALADOR_TELEPORT, falPatch); farmPatch(); tpAndMoveToArea(Spells.NormalSpells.ARDOUGNE_TELEPORT, ardyPatch); farmPatch(); } else { log("Not enough supplies to perform a herb run"); stop(); } */ This neeeds some looping structure if bot-has-items if !bot-near-patch || patch-has-herb move-to-next else farmpatch else get-items return random(500, 1200); } private boolean checkSupplies() throws InterruptedException { String[] items = new String[]{"Rake", "Seed dibber", "Spade", "Ectophial"}; String[] runes = new String[]{"Law rune", "Water rune", "Air rune"}; for (String item : items) { if (!getInventory().contains(item)) { log(item + " not found"); return false; } } for (String rune : runes) { if (getInventory().getAmount(rune) < 10) { log(rune + " not found"); return false; } } long seedAmount = getInventory().getAmount((x) -> x.getName().contains("seed")); long compostAmount = getInventory().getAmount((x) -> x.getName().contains("post")); if (seedAmount < 4/* && compostAmount < 4*/) { log("Seed or Compost fail" + seedAmount); return false; } return true; } private void noteHerbs() throws InterruptedException { Item myItem = getInventory().getItem((x) -> x.nameContains("Grimy") && !x.isNote()); myItem.interact("Use"); if (getInventory().isItemSelected()) { NPC tl = npcs.closest("Tool Leprechaun"); tl.interact("Use"); Sleep.sleepUntil(() -> !myPlayer().isMoving(), 5000); } } private void banking() throws InterruptedException { if (getBank().open()) { getBank().depositAll("Bucket"); getBank().depositAll(21483); getBank().withdraw(21483, 5); } } private void moveToMort() throws InterruptedException { Position myspot = myPlayer().getPosition(); getInventory().getItem("Ectophial").interact("Empty"); Sleep.sleepUntil(() -> !myPlayer().getPosition().equals(myspot), 5000); walking.webWalk(mortPatch); } private void moveToCamelot() throws InterruptedException { log("Let's get started!"); tpAndMoveToArea(Spells.NormalSpells.CAMELOT_TELEPORT,camBank); banking(); walking.webWalk(camelotPatch); } private void tpAndMoveToArea(MagicSpell spell, Area area) throws InterruptedException { Position myspot = myPlayer().getPosition(); magic.castSpell(spell); Sleep.sleepUntil(() -> !myPlayer().getPosition().equals(myspot), 5000); walking.webWalk(area); } private void farmPatch() throws InterruptedException { if (getInventory().contains((x) -> x.nameContains("Grimy") && !x.isNote())){ noteHerbs(); }else { RS2Object patch = getObjects().closest(8150,8151,8152,8153); if (patch needs to be raked){ rake }else if(inventory has weeds){ drop weeds }else if(patch can be picked){ pick patch }else if(patch is empty and has no weeds and no compost){ use compost }else { use use seed } } } } Quote Link to comment Share on other sites More sharing options...