Zuul 3 Posted November 26, 2021 Hi there, I want to contribute to the community, so here is my gnome agility script. Programming is not my way of living and i don't do a lot of it. Been making script since... Long time ago and for diff. clients. In the past, the community helped me understand the client and api and how a script is structured, from basic scripts to advanced frameworks. Im using Eclipse IDE on windows and the JAVADOCS for this client. There are excellent tutorials on the net on how to install Eclipse and Java, just google it. And i always run the client in resizeable mode - modern layout. Or resizeable mode - classic layout. Because i want to and i am always watching my script run. Im lazy when coding, so i've made a few rewrites, eg. #MethodProvider.getLocalPlayer() i rewrote to #player(). And for my random numbers, i use ThreadLocalRandom (see ThreadLocal...), eg. #nextInt(lowEndValue, highEndValueExclusive). Etc., see script - helper functions Spoiler private Player player() { return getLocalPlayer(); } I've adjusted the basic script layout (see scripter-guide), to my needes - you should do the same and find the layout that works for you. Theres nothing right and wrong about it, just as long as it fulfil one's task. Just fiddle with it, and over time you'll get more skilled and perhaps one day reach level 99 😉. Don't be like all other ppl, BotWatch is all about patterns, right? The guides on this site is pretty okay and it's getting better every day, just be wary of deprecated methods (see javadocs skilltracker), that will stop your script eventually, if you dont correct 'em... There is alot to understand, when scripting. Like when you click on an item in game, eg. a ladder, you don't go up the ladder straight away. You might if your next to the ladder, but if you are 2 or more tiles away, then you have to move to the ladder first. So you have to subdivide 'climb ladder' into smaller time arranged units first. And that's how you program your script... 1. If you are not close to the ladder, when interacting it, you'll have to (automatically) walk to it first 2. Lets assume you are standing still. So from this starting point, we first have to wait for movement, after we have clicked on the ladder/interacting with it 3. After we have started moving, we'll have to decide: a) wait until we have stopped moving or b) are within a certain distance to our target location or c) start doing the desired action 4. Wait until desired action is completed (eg. we are up a floor) Above situation is the same for almost all actions in the game, either you are close to the entity or not. If not close, then you have to move first. Then as most humans do, whenever we are close, we start interacting with it. We normally dont wait for the game ppl to stop moving, before we start another action. This applies for mining, fishing, combat, etc. Applies for every interaction with entities, where you have to be next to it, for any action to occur. Then you have to consider: is it reachable?, is it already being interacting with by another player, is it ready?, are all conditions satisfied? etc, etc. First i've enabled some settings in the client, to get information about my surroundings in game: Spoiler I've looked at the wiki for the gnome agility course, and made a method for each part of the agility course, #01 to #07 For each part, i used the mouse to get information about the different entities in game. Spoiler Collecting the ID's for entities used in the script Main loop of the script is divided into the different parts of the course. Spoiler #01 to #07 in the script For the most time, i can use positions (x, y and z) to determine the ppl location on the course. Needed a few area's for help, but you can do without 'em. The script works fine, but its easy to see, its not perfect when you watch it run. Its basic, with no bells and whistles. There are lots of optimisations to be made and lots of checks to expand, for it to run fine and self correcting when it encounters hickups/errors made. The script it here: Sorry for format is not up to par... Spoiler package org.zuul.simple.pay.agility.gnome; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.util.concurrent.BlockingDeque; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.ThreadLocalRandom; import org.dreambot.api.Client; import org.dreambot.api.methods.dialogues.Dialogues; import org.dreambot.api.methods.interactive.GameObjects; import org.dreambot.api.methods.map.Area; import org.dreambot.api.methods.skills.Skill; import org.dreambot.api.methods.skills.SkillTracker; import org.dreambot.api.methods.skills.Skills; import org.dreambot.api.methods.walking.impl.Walking; import org.dreambot.api.script.AbstractScript; import org.dreambot.api.script.Category; import org.dreambot.api.script.ScriptManager; import org.dreambot.api.script.ScriptManifest; import org.dreambot.api.script.listener.ChatListener; import org.dreambot.api.wrappers.interactive.GameObject; import org.dreambot.api.wrappers.interactive.Player; import org.dreambot.api.wrappers.widgets.message.Message; @ScriptManifest(author = "Zuul", category = Category.AGILITY, description = "Gnome Stronghold Agility", name = "Gnome Stronghold Agility", version = 1.0) public final class ZuulGnomeAgility extends AbstractScript implements ChatListener { // --__--__--__--__--__--__--__--__--__--__--__--__--__-- // __--Main part of the dreambot script__--__--__--__--__ // --__--__--__--__--__--__--__--__--__--__--__--__--__-- //see https://dreambot.org/javadocs/org/dreambot/api/script/AbstractScript.html @Override //Before we start running our script public void onStart() { doActionsOnStart(); } @Override //After we are done running our script public void onExit() { doActionsOnExit(); } @Override //Our script public int onLoop() { performLoopActions(); return nextInt(60, 75); } @Override //Paint Stat's and Data public void onPaint(Graphics2D g2) { doDraw(g2); } // --__--__--__--__--__--__--__--__--__--__--__--__--__-- // __--Implements--__--__--__--__--__--__--__--__--__--__ // --__--__--__--__--__--__--__--__--__--__--__--__--__-- //see https://dreambot.org/javadocs/org/dreambot/api/script/listener/ChatListener.html @Override //Get and handle player messages, if any public void onPlayerMessage(Message msg) { handlePlayerMessage(msg); } @Override //Get and handle game messages, if any public void onMessage(Message msg) { handleGameMessages(msg); } // --__--__--__--__--__--__--__--__--__--__--__--__--__-- // __--Helper functions__--__--__--__--__--__--__--__--__ // --__--__--__--__--__--__--__--__--__--__--__--__--__-- private void doActionsOnStart() { startTime = System.currentTimeMillis(); //save current number of system millis elapsed (long value) SkillTracker.start(Skill.AGILITY); //see https://dreambot.org/javadocs/org/dreambot/api/methods/skills/SkillTracker.html oldAgilityExp = Skills.getExperience(Skill.AGILITY); //record start agility experience Walking.setRunThreshold(nextInt(81, 92)); //set run threshold between 81 and 91 percent sleep(100); //wut? log("Starting Zuul Script"); //write to console, that we are starting this script } private void doActionsOnExit() { log(String.format("Gained agility xp: %d", (Skills.getExperience(Skill.AGILITY) - oldAgilityExp))); log("Runtime: " + getElapsedTimeAsString()); } private void performLoopActions() { //see https://dreambot.org/javadocs/org/dreambot/api/script/ScriptManager.html //see https://dreambot.org/javadocs/org/dreambot/api/Client.html if (ScriptManager.getScriptManager().isRunning() && Client.isLoggedIn()) { //handleDialogues(); //Close open dialogues. Should be invoked between each obstacle/part... //see https://oldschool.runescape.wiki/w/Gnome_Stronghold_Agility_Course doLogBalance(); //# 01 logs doObstacleNetIn(); //# 02 net inwards doTreeBranchUp(); //# 03 branch up doBalancingRope(); //# 04 rope doTreeBranchDown(); //# 05 branch down doObstacleNetOut(); //# 06 net outwards doObstaclePipe(); //# 07 pipe } } private void doDraw(Graphics2D g2) { //separate thread from main script loop g2.setRenderingHints(antialiasing); g2.setFont(infoFont); g2.setColor(new Color(0, 255, 255, 65)); g2.drawRect(0, 338, 518, 140); g2.setColor(new Color(0, 0, 0, 65)); g2.fillRect(1, 339, 516, 138); g2.setColor(new Color(0, 204, 0, 210)); g2.drawString("Run time: " + getElapsedTimeAsString(), 12, 360); g2.drawString("Agility Lvl: " + Skills.getBoostedLevels(Skill.AGILITY), 12, 370); g2.drawString("Exp/Hr: " + SkillTracker.getGainedExperiencePerHour(Skill.AGILITY), 12, 380); g2.drawString("Time Till Level: " + makeTimeString(SkillTracker.getTimeToLevel(Skill.AGILITY)), 12, 390); if (deque.size() > 0) { g2.setColor(new Color(255, 255, 255, 220)); final int px = 10; final int dy = 014; int py = 50; int loopC = 1; for (String s: deque) { g2.drawString(s, px, (py + (dy * loopC++))); } } } // --__--__--__--__--__--__--__--__--__--__--__--__--__-- // __--Helper functions__--__--__--__--__--__--__--__--__ // --__--__--__--__--__--__--__--__--__--__--__--__--__-- private void handleDialogues() { if (Dialogues.inDialogue()) { // see https://dreambot.org/javadocs/org/dreambot/api/methods/dialogues/Dialogues.html for (int i = 0; i<4; i++) { if (Dialogues.canContinue()) { // Dialogues.continueDialogue(); // sleep(nextInt(500, 750)); // } else { break; //break out of loop, if no more dialogues } } closedDialogues++; } } private String getElapsedTimeAsString() { return makeTimeString(getElapsedTime()); //make a formatted string from a long value } private long getElapsedTime() { return System.currentTimeMillis() - startTime; //return elapsed millis since start of script } private String makeTimeString(long ms) { final int seconds = (int)(ms / 1000) % 60; final int minutes = (int)((ms / (1000 * 60)) % 60); final int hours = (int)((ms / (1000 * 60 * 60)) % 24); final int days = (int)((ms / (1000 * 60 * 60 * 24)) % 7); final int weeks = (int)(ms / (1000 * 60 * 60 * 24 * 7)); if (weeks > 0) { return String.format("%02dw %03dd %02dh %02dm %02ds", weeks, days, hours, minutes, seconds); } if (weeks == 0 && days > 0) { return String.format("%03dd %02dh %02dm %02ds", days, hours, minutes, seconds); } if (weeks == 0 && days == 0 && hours > 0) { return String.format("%02dh %02dm %02ds", hours, minutes, seconds); } if (weeks == 0 && days == 0 && hours == 0 && minutes > 0) { return String.format("%02dm %02ds", minutes, seconds); } if (weeks == 0 && days == 0 && hours == 0 && minutes == 0) { return String.format("%02ds", seconds); } if (weeks == 0 && days == 0 && hours == 0 && minutes == 0 && seconds == 0) { return String.format("%04dms", ms); } return "00"; } private void handlePlayerMessage(Message msg) { //separate thread from main script loop final String aMsg = msg.getMessage(); final String pplName = msg.getUsername(); log(String.format("%d, %d", msg.getTime(), msg.getTypeID())); } private void handleGameMessages(Message msg) { //separate thread from main script loop final String aMsg = msg.getMessage(); final int aSum = zuulH(aMsg); //sum all char's in the string returned from game messages //meh #string.contains(...); log(aMsg + " | " + aSum); // 18:16:32: [SCRIPT] You fail to pick the man's pocket. | 3054 // switch (aSum) { // case 3054: // globalVariable_IfTrueDoSomeThing = true; // break; // } deque.add(aMsg + " " + aSum); //add the message and encoded int to the queue for display if (deque.size() > 10) { //only keep the 10 newest messages deque.removeFirst(); } } private int zuulH(String x) { //sum all char's in the string and return it final char ch[] = x.toCharArray(); int i, sum; for (sum = 0, i = 0; i<x.length(); i++) { sum += ch[i]; } return sum; } private int nextInt(int valIncluded) { //get a random value return ThreadLocalRandom.current().nextInt(valIncluded); } private int nextInt(int lowValIncluded, int highValExcluded) { //get a random value between a range, high end is not included return ThreadLocalRandom.current().nextInt(lowValIncluded, highValExcluded); } private Player player() { //get the local player, less typing return getLocalPlayer(); } private int playerX() { //get player x location return player().getX(); } private int playerY() { //get player y location return player().getY(); } private int playerZ() { //get player z location return player().getZ(); } private boolean isMoving() { //true if player is moving return player().isMoving(); } private boolean isAnimating() { //true if player is animating. NOT all animations in game results in a true return value return player().isAnimating(); //eg. walking on a agility log (arms stretched to the sides), does not return true here } private boolean atStartArea() { //area before the agility log return startArea.contains(player()); } private boolean atAfterLogArea() { //area after the agility log return afterLogArea.contains(player()); } // --__--__--__--__--__--__--__--__--__--__--__--__--__-- // __--Script functions__--__--__--__--__--__--__--__--__ // --__--__--__--__--__--__--__--__--__--__--__--__--__-- private void doLogBalance() { if (atStartArea()) { final GameObject aLog = GameObjects.closest(23145); if (aLog != null) { if (aLog.distance() > 9) { //more than 9 squares away, so walk. Wait until we start walking Walking.walk(aLog); //walks via mini-map to clicked destination near entity //see https://dreambot.org/javadocs/org/dreambot/api/methods/MethodProvider.html sleepUntil(() -> isMoving(), nextInt(500, 1000)); //wait a random time, between 500 and 999 millis. Exit sleep as soon as we register movement, else sleep time } //see https://dreambot.org/javadocs/org/dreambot/api/methods/MethodProvider.html //do some sleeping, exit sleep when we are within 2-4 squares our walking destination or time has elapsed (3600-4000 millis) //in that time period, between 3600 and 3999 millis, every 320 to 479 millis, check if we are moving. If so, then reset timer sleepUntil( () -> (player().distance(Walking.getDestination())<= nextInt(3, 5)), () -> isMoving(), nextInt(3600, 4000), //timer duration nextInt(320, 480)); //every time, poll timer is up, check reset condition. If true, then reset timer duration if (aLog.interact()) { //click the log to walk on it sleepUntil( () -> playerY() == 3429, //sleep until we have reached the other end of the log () -> isMoving(), //reset timer if we move nextInt(1000, 2000), //only sleep between 1000 millis to 1999 millis (1 second to almost 2 seconds) nextInt(320, 480) //every - between 320 to 479 elapsed millis, check condition (movement) ); } } } } private void doObstacleNetIn() { if (atAfterLogArea()) { final GameObject aNet = GameObjects.closest(23134); if (aNet != null) { if (aNet.interact()) { sleepUntil(() -> isMoving(), nextInt(500, 1000)); sleepUntil( () -> playerZ() == 1, //sleep until we go 1 level up in floors () -> isMoving(), nextInt(1000, 2000), nextInt(320, 480) ); } } } } private void doTreeBranchUp() { if (playerZ() == 1) { final GameObject aBranchUp = GameObjects.closest(23559); if (aBranchUp != null) { if (aBranchUp.interact()) { sleepUntil(() -> isMoving(), nextInt(500, 1000)); sleepUntil( () -> playerZ() == 2, //sleep until we go 1 level up in floors () -> isMoving(), nextInt(1000, 2000), nextInt(320, 480) ); } } } } private void doBalancingRope() { if (playerZ() == 2) { /*Check on which side of the balancing rope we are*/ if (playerX()<2478) { //we are on the correct side of the rope final GameObject aRope = GameObjects.closest(23557); if (aRope != null) { if (aRope.interact()) { sleepUntil(() -> isMoving(), nextInt(500, 1000)); sleepUntil( () -> playerX() == 2483, //sleep until we are at the other end of the rope () -> isMoving(), nextInt(1000, 2000), nextInt(320, 480) ); } } } } } private void doTreeBranchDown() { if (playerZ() == 2) { /*Check on which side of the balancing rope we are*/ if (playerX() >= 2483) { //we are on the correct side of the rope final GameObject aBranchDown = GameObjects.closest(23560); if (aBranchDown != null) { if (aBranchDown.interact()) { sleepUntil(() -> isMoving(), nextInt(500, 1000)); //sleep/wait until we start moving sleepUntil(() -> playerZ() == 0, nextInt(3000, 3500)); //sleep until we reach ground floor } } } } } private void doObstacleNetOut() { if (playerZ() == 0 && playerY()<3426) { final GameObject aNetOut = GameObjects.closest(23135); if (aNetOut != null) { if (aNetOut.interact()) { sleepUntil(() -> isMoving(), nextInt(500, 1000)); sleepUntil( () -> playerY() == 3428, //we are on the correct side of the net () -> (isMoving() || isAnimating()), nextInt(1000, 2000), nextInt(320, 480) ); } } } } private void doObstaclePipe() { if (playerZ() == 0 && (playerY() > 3426 && playerY()<3431)) { // after net out and before pipes final GameObject aPipe = GameObjects.closest(23138); if (aPipe != null) { if (aPipe.interact()) { sleepUntil(() -> isMoving(), nextInt(500, 1000)); sleepUntil(() -> playerY() == 3437, //we are on the other side of the pipe () -> (isMoving() || isAnimating()), nextInt(4000, 5000), nextInt(500, 600) ); } } } } // --__--__--__--__--__--__--__--__--__--__--__--__--__-- // __--Filters and variables_--__--__--__--__--__--__--__ // --__--__--__--__--__--__--__--__--__--__--__--__--__-- // https://explv.github.io/?centreX=3066¢reY=3316¢reZ=0&zoom=8 private final RenderingHints antialiasing = new RenderingHints( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); private final Font infoFont = new Font("Monospaced", 0, 12); private final Area startArea = new Area(2471, 3439, 2488, 3436); // see https://dreambot.org/javadocs/org/dreambot/api/methods/map/Area.html private final Area afterLogArea = new Area(2470, 3429, 2477, 3425); private final BlockingDeque<String> deque = new LinkedBlockingDeque<String> (); private int closedDialogues = 0; private int oldAgilityExp = 0; private long startTime = 0; // --__--__--__--__--__--__--__--__--__--__--__--__--__-- // __--__--__--__--__--__--__--__--__--__--__--__--__--__ // --__--__--__--__--__--__--__--__--__--__--__--__--__-- }
EnvyXan 3 Posted November 29, 2021 I love a nice in depth thread rather than a few words and a source. Thanks for taking the time. Nicely done!
javabrotato 1 Posted August 9, 2022 I'm just getting started scripting and this was extremely helpful to me. Thanks a lot for sharing ^^
Recommended Posts
Archived
This topic is now archived and is closed to further replies.