Jump to content
Frequently Asked Questions
  • Are you not able to open the client? Try following our getting started guide
  • Still not working? Try downloading and running JarFix
  • Help! My bot doesn't do anything! Enable fresh start in client settings and restart the client
  • How to purchase with PayPal/OSRS/Crypto gold? You can purchase vouchers from other users
  • Try asking for help in the chatbox
  • Gnome Stronghold Agility Course


    Zuul
     Share

    Recommended Posts

    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

    110291021_2-K.png.06e0a1c3d680c22694a96d7dffa4fbd4.png

    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

    1438090852_3-K.png.0ad836ca2ed72776e9982470c3e9037b.png283489607_4-K.png.87fa224a7b71a1ab8362df263091a83c.png1372063274_5-K.png.e96f58aad68f8b47bc166e95955902e6.png31336702_6-K.png.a895ba006c1c450a2b03139f795fdeaa.png 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

    1963076771_7-K.png.1368c323a0f30b4205d59e8eeac3978c.png #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&centreY=3316&centreZ=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;
    
      // --__--__--__--__--__--__--__--__--__--__--__--__--__--
      // __--__--__--__--__--__--__--__--__--__--__--__--__--__
      // --__--__--__--__--__--__--__--__--__--__--__--__--__--
    
    }

     

     

    Edited by Zuul
    Format
    Link to comment
    Share on other sites

    • 8 months later...

    Create an account or sign in to comment

    You need to be a member in order to leave a comment

    Create an account

    Sign up for a new account in our community. It's easy!

    Register a new account

    Sign in

    Already have an account? Sign in here.

    Sign In Now
     Share

    ×
    ×
    • Create New...

    Important Information

    We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.