Welcome to TRiBot Forums

Register now to gain access to all of our features. Once registered and logged in, you will be able to contribute to this site by submitting your own content or replying to existing content. You'll be able to customize your profile, receive reputation points as a reward for submitting content, while also communicating with other members via your own private inbox, plus much more! This message will be removed once you have signed in.

TRiLeZ

TRiLeZ's Scripting Tutorial

38 posts in this topic

TRiLeZ's Scripting Tutorial

 

The purpose of this tutorial is to teach the basics of coding for TRiBot. This tutorial assumes you have basic/some knowledge of Java. If you don't, try learning a little bit of Java before reading this tutorial.
 
Even though this tutorial is mostly just covering the basics, intermediate scripters may find this tutorial useful. So please intermediates, read this. Sections 5, 6, and 7 are most valuable to intermediates, but the other sections might help too.
 
1. Requirements

2. Setting Up Eclipse

  • Find a tutorial elsewhere to do this, if Eclipse isn't set up.

3. Resources

4. Writing the Script: Getting Started

  • Time to jump into the script.
  • Before reading below, you need to understand the following:
    • If I use an API method which you aren't familiar with, look for it in the API documentation, and read all of the comments about the method. The documentation is your friend.
  • Create a new class name. Make the class extend Script (you'll have to import org.tribot.script.Script).
  • Now, implement the abstract methods of Script into your script class. See the API for which methods to implement.
package scripts;
import org.tribot.script.Script;

public class TutorialScript extends Script {
 @Override
 public void run() {

 }
}
  • When the script is executed, the run() method will be called. When the thread exits the run() method, the script will stop. Therefore, we will need to have a loop to make sure we don't leave the run method until we want the script to stop.
package scripts;
import org.tribot.script.Script;

public class TutorialScript extends Script {
 @Override
 public void run() {
  while (true) {
   sleep(10);
  }
 }
}
  • You'll notice that I added "sleep(10);" What this does is it makes the script sleep for 10 milliseconds. The reason for doing this is to prevent the script from using max CPU. Without the sleep, the script will try to execute the contents of the loop as many times as possible, and as fast as possible, which is very CPU intensive. Having a sleep will prevent this.
  • Now, we should try to figure out how to structure the main loop of the script. The structure depends on what activity the script will be performing. For this script, we are going to make a basic Draynor willow cutter and banker. Note: I won't be testing this script, nor will I be using 100% correct tiles, IDs, or names.
  • I will make the structure first check the area in which the player is in. Then, the script will check other conditions to determine what to do.
  • The following script is how I decided to structure this script. All of the new methods written are stubs and we will fill them in soon.
package scripts;
import org.tribot.api2007.Inventory;
import org.tribot.script.Script;

public class TutorialScript extends Script {

 /**	 
  * Checks if we are at the trees.
  * 	
  * @return True if we are at the trees; false otherwise.	
  */
 private boolean isAtTrees() {
  return false;
 }

 /**	 
  * Checks if we are in the bank.	
  * 	
  * @return True if we are in the bank; false otherwise.	
  */
 private boolean isInBank() {
  return false;
 }

 /**	 
  * Attempts to cut a tree. If we are already cutting a tree, we will wait	 
  * until that tree has been cut.	 
  * 	 
  * @return True if we were able to cut the tree; false otherwise.	 
  */
 private boolean cut() {
  return false;
 }

 /**	 
  * Checks if we are cutting a tree.	
  * 	 
  * @return True if were are cutting a tree; false otherwise.	
  */
 private boolean isCutting() {
  return false;
 }

 /**	 
  * Attempts to walk to the bank.	
  * 	 
  * @return True if we were able to walk to the bank; false otherwise.	 
  */
 private boolean walkToBank() {
  return false;
 }

 /**	
  * Attempts to walk to the trees.	
  * 	
  * @return True if we were able to walk to the trees; false otherwise.
  */
 private boolean walkToTrees() {
  return false;
 }

 /**	 
  * Attempts to bank our items.
  * 	
  * @return True if we were successfully able to bank the items;
  * false otherwise.         
  */
 private boolean bank() {
  return false;
 }

 @Override
 public void run() {
  while (true) {
   sleep(50);
   if (isAtTrees()) { // We are at the trees		
    // Time to check what to do. If the inventory is full, we should	
    // walk to the bank. Otherwise, we should cut the willows.	
    if (Inventory.isFull()) { // The inventory is full	
     walkToBank(); // Let's walk to the bank			
    } else // The inventory is not full	
     cut(); // Let's cut the willows.	
   } else if (isInBank()) { // We are at the bank	
    // Time to check what to do. If the inventory is full, we should	
    // bank the items. Otherwise, we should walk back to the trees.		
    if (Inventory.isFull()) // The inventory is full		
     bank(); // Let's bank the items		
    else  // The inventory is not full	
     walkToTrees(); // Let's walk to the trees.		
   } else { // We are neither in the bank, nor at the willows		
    // Time to check what to do. If the inventory is full, we will	
    // walk to the bank. Otherwise, we will walk to the willows.	
    if (Inventory.isFull()) // Inventory is full		
     walkToBank(); // Walk to the bank			
    else // Inventory is not full		
     walkToTrees(); // Walk to the trees.	
   }
  }
 }
}
  • Assuming you know how the flow of execution is, the comments should be fairly easy to follow, and should explain everything.
  • Now, let's fill in isAtTrees(). How should we do this? Let's find the nearest willow tree, and see if it is on-screen.
	private boolean isAtTrees() {
	 // We search for the trees by their name - Willow. The means that we	
	 // will search for the trees within a radius of 20 tiles from our	
	 // character. If they are more than 20 tiles away, the findNearest
	 // method will not find them. Although, if they are more than 20 tiles
	 // away, we can be sure that they aren't on the screen.	
	 // We will now store the variable returned form findNearest in the	
	 // variable called 'willows'. We declare this variable final because we	
	 // will not be changing it's contents after the variable is set.
	 // According to the API, the returned value from findNearest will be
	 // RSObject[]. If there are no trees found, the array will not contain
	 // any elements. The returned value cannot be null, and therefore we
	 // don't have to null check it.		
	 // Next, we check the length of the array. If the length is less than 1,	
	 // we know that no trees were found. We can now return false.
	 final RSObject[] willows = Objects.findNearest(20, "Willow");
	 if (willows.length < 1)
	  return false;
	 // The array contains at least one element. The first element in the
	 // array will be the nearest tree to our character. Let's check if this
	 // tree is on screen. We will return the value.	
	 return willows[0].isOnScreen();
	}
  • Now, we will fill in the isAtBank() method. We will check if either a bank booth, or banker is on-screen. I will explain things in less detail this time since the details above apply to some of the code below.
	private boolean isInBank() {
	 // Let's first search for on-screen booths.	
	 final RSObject[] booths = Objects.findNearest(20, "Bank booth");
	 if (booths.length > 1) { // A booth is in the array. Let's check if the first element of the		
	                          // array is on the screen.		
	  if (booths[0].isOnScreen())
	   return true;
	  // The booth is on the screen. We don't need to
	  // check for visible bankers since we already know	
	  // that we are in the bank. Let's exit this method	
	  // and return true.			
	 }
	 
	  // Nope, the nearest booth is no visible. Let's go and and search	
	  // for bankers.		
	 final RSNPC[] bankers = NPCs.findNearest("Banker");
	 if (bankers.length < 1)
	  return false; // No booths are on the screen, and no bankers exist.	
	                // Let's just exit already since we know that we are		
	                // not in the bank. We will return false.	

	 // Okay, so we found a banker. The first element in the array is the	
	 // nearest NPC. Let's check if that NPC is on-screen.	
	 return bankers[0].isOnScreen(); // Return whether or not the banker is on	
	                                 // the screen. If it is, we are in the			
	                                 // bank; if not, then we are not in the		
	                                 // bank.
	}
  • Now, let's fill in cut(). We will first check if we are already cutting. If we are, then we will wait until we are not cutting anymore. If we are not cutting, we will attempt to cut the tree.
	private boolean cut() {
	 if (isCutting()) {
	  final long timeout = System.currentTimeMillis() + General.random(60000, 90000); 
      // Let's define a timeout for the loop below. If we don't have a
	  // timeout, it is possible that the script will enter an infinite
	  // loop, and will therefore be stuck. We set the timeout for the
	  // current time plus somewhere between 60 and 90 seconds. We use
	  // randomness to avoid seeming bot-like.
	  while (isCutting() && System.currentTimeMillis() < timeout) {
	   sleep(100, 150); // We will loop while we are cutting, and while the current time			
	   // is before the timeout. Make sure to have a sleep to prevent a	CPU overload.				
	   // We could also implement some anti-ban features here if we	
	   // want.			
	   // Now, let's check if the willow tree is still at the location	
	   // of the last clicked location. To do this, we will define a	
	   // global variable - last_tree_tile - of type RSTile. The	
	   // variable will be defined below, when we find and click a	
	   // tree.			
	   // Make sure to null check the variable, since it can be null.
	   // If it is null and we try to perform actions upon it, a Null	
	   // Pointer Exception will be thrown, crashing the script.	
	   if (this.last_tree_tile != null) {
	    // The variable is not null. We can use it now.			
	    if (!Objects.isAt(this.last_tree_tile, "Willow")) {
	     // The willow tree is gone. It has either been chopped		
	     // down, or turned into an ent. Let's break out of this		
	     // loop.	
	     break; // Good-bye loop	
	    }
	   }
	  }
	 }
	 // Let's go find a tree to chop.
	 final RSObject[] trees = Objects.findNearest(50, "Willow");
	 // Search for the willow within 50	tiles
	 // from our character.		
	 if (trees.length < 1)
	  return false; // No trees have been found. We can't do anything, so	
	 // let's exit this method.

	 if (!trees[0].isOnScreen()) {
	  // The nearest tree is not on the screen. Let's walk to it.	
	  if (!Walking.walkPath(Walking.generateStraightPath(trees[0]))) 
      // We could not walk to the tree. Let's exit so we don't try	
	  // clicking a tree which isn't on screen.
	   return false;

	  if (!Timing.waitCondition(new Condition() { 
        // We will now use the Timing API to wait until the tree is on	
	    // the screen (we are probably walking to the tree right now).	
	    @Override
	    public boolean active() {
	     General.sleep(100); // Sleep to reduce CPU usage.
	     return trees[0].isOnScreen();
	    }
	   }, General.random(8000, 9300)))
	  // A tree could not be found before the timeout of 8-9.3	
	  // seconds. Let's exit the method and return false. we don't		
	  // want to end up trying to click a tree which isn't on the
	  // screen.		
	   return false;
	 }
	 // Okay, now we are sure trees[0] is on-screen. Let's click it. We may	
	 // be still moving at this moment, so let's use DynamicClicking.		
	 // DynamicClicking should be used when your character is moving, or the	
	 // target is moving, and you need to click the target.	
	 if (!DynamicClicking.clickRSObject(trees[0], "Chop down")) 
     // We could not click the tree. Let's exit the method since we		
	 // failed.
	  return false;
	 // We clicked the tree. Let's first wait to stop chopping for 1-1.2	
	 // seconds just in case we moved on to this tree while still performing		
	 // the chopping animation.	
	 Timing.waitCondition(new Condition() {
	  @Override
	  public boolean active() {
	   return !isCutting();
	  }
	 }, General.random(1000, 1200));
	 // We don't need to if check it since the result doesn't matter.		
	 if (Timing.waitCondition(new Condition() {
	   // Now let's wait until we are cutting.			
	   @Override
	   public boolean active() {
	    return isCutting();
	   }
	  }, General.random(8000, 9000))) {
	  // We are cutting! Now let's record the tree's tile and return true.			
	  this.last_tree_tile = trees[0].getPosition().clone(); 
      // getPosition() can never be null, so we don't need to null check		
	  // it.		
	  return true;
	 }
	 // We failed to cut a tree. Return false.	
	 return false;
	}
  • Now, let's fill out isCutting(). We will simply check the animation.
private boolean isCutting() {
 return Player.getAnimation() > 0; // If the animation ID is greater than			
 // 0, then we are animating. Let's		
 // assume that if were are							
 // animating, that the animation is		
 // the chopping one.	
}
  • Now let's fill out walkToBank(). Since we are lazy, we will just use web walking.
	private boolean walkToBank() {
	 if (!WebWalking.walkToBank()) { // We failed to walk to the bank. Let's return false.	
	  return false;
	 }
	 // Walking succeeded, but we may still be moving, and not our destination	
	 // yet. Let's wait until we are in the bank.	
	 return Timing.waitCondition(new Condition() { // If we reach the bank before the timeout, this method will return		
	                                               // true. Otherwise, it will return false.			
	  @Override public boolean active() {
	   General.sleep(200, 300); // Reduces CPU usage.		
	   return isInBank();
	  }
	 }, General.random(8000, 9000));
	}
  • Now, let's fill out the walkToTrees() method. Once again, we will use web walking. We will search for the nearest willow tree to determine which tile to walk to.
	private boolean walkToTrees() {
	 final RSObject[] willows = Objects.findNearest(50, "Willow");
	 if (willows.length < 1) // No willows could be found. We cannot do anything. Let's exit this		
	 // method.		
	  return false;
	 // Let's walk to the closest willow tree now.	
	 if (!WebWalking.walkTo(willows[0]))
	 // We failed to walk to the bank. Let's return false.	
	  return false;
	 // Walking failed, but we may still be moving, and not our destination	
	 // yet. Let's wait until we are at the trees.		
	 return Timing.waitCondition(new Condition() { // If we reach the trees before the timeout, this method will return	
	                                               // true. Otherwise, it will return false.	
	  @Override public boolean active() {
	   General.sleep(200, 300); // Reduces CPU usage.	
	   return isAtTrees();
	  }
	 }, General.random(8000, 9000));
	}
  • Last method for our basic script; bank(). First, we will check if the bank screen is open. If it is not open, we will open it. Once opened, we will bank our logs.
	private boolean bank() {
	 if (!Banking.isBankScreenOpen()) { // The bank screen is not open. Let's open it.		
	  if (!Banking.openBank())
	  // Could not open the bank. Let's return false.		
	   return false;
	  // Since openBank() will wait for the bank screen to be open before	
	  // returning true, it is safe to assume that the bank screen is now		
	  // open.		
	 }
	 // Now let's deposit the logs. We will check if an axe is in our	
	 // inventory. If there is one, we will bank by using our inventory	
	 // items. Otherwise, we will just click the deposit all button.	
	 // Let's define our axe names now. It is better to define variables like	
	 // this globally, but we only use the axe names within this method, so I	
	 // don't feel the need to.		
	 final String[] axe_names = {
	  "Bronze axe",
	  "Iron Axe",
	  "Black Axe",
	  "Steel Axe",
	  "Mithril Axe",
	  "Adamant Axe",
	  "Rune Axe",
	  "Dragon Axe"
	 };
	 if (Inventory.find(axe_names).length > 0) { 
       // If the length of the returned value if greater than one, that		
	   // means we have an axe in our inventory.	
	  if (Banking.depositAllExcept(axe_names) < 1)
	  // We failed to deposit our items. Let's exit and return false.		
	   return false;
	 } else {
	  if (Banking.depositAll() < 1)
	  // We failed to click the deposit all button. Let's exit and return false.	
	   return false;
	 }
	 // Okay, our items should get deposited. Let's wait and make sure they
	 // get deposited.		
	 return Timing.waitCondition(new Condition() { // Since we can only enter the bank method if our inventory is full,	
                                            	   // let's wait until our inventory is not full. If it is not full	
                                            	   // before the timeout, return true. Otherwise, return false.		
	  @Override
	  public boolean active() {
	   return !Inventory.isFull();
	  }
	 }, General.random(3000, 4000));
	}
  • We have finished coding the basic functionality of the script. We forgot to include a Script Manifest, so let's do that now. A Script Manifest tells the Script Manager details about our script. To do this, we include the ScriptManifest (org.tribot.script.ScriptManifest) runtime annotation right above the defining of the script class.
@ScriptManifest(authors = { "TRiLeZ" }, category = "Woodcutting", name = "Basic Willow Cutter", version = 1.00, description = "Cuts and banks willows in Draynor.", gameMode = 1)

public class TutorialScript extends Script {
  • We have finished writing a basic Draynor willow cutter and banker. We could go further and add more features and functionality such as paint, but that will be covered in a different tutorial.
  • Let's move on.

5. Scripting Tips

  • When piecing together a script, try and test each method piece by piece. Doing this makes sure that code is functional before moving on to coding another section. It was make things easier when you finish writing the script, and try testing for the first time. The script may not work correctly on the first try, and might need to be modified in a bunch of methods. Doing testing piece by piece will reduce the amount of end modifications needed, and it will also help you find bugs easier.
  • Avoid linear coding. If one action fails in a line of actions, the script will try to perform the next actions, but will fail to do so, and will screw up. Check the returned value of API methods. If the method failed to do something, or if requirements aren't met, then don't execute the code that follows.
    • Another benefit to not using linear coding is being able to start the script at any location/state, and the script will be able to pickup where you are, and continue to do what is needed. With linear scripts, you are restricted to starting at a certain location/state. Don't restrict your users that way.
  • Read the source code of others; specifically, from scripters who have more scripting knowledge than you. I have a bunch of open source RS3 scripts. Those may not be the same as an Old-School script, but they'll show you a great script structure, and other great scripting mechanics.
  • Read the TRiBot API documentation.

6. Things to Check For

  • NullPointerException (NPEs)
    • These occur when a variable is null, and you try to perform an action (other than a null check) on that variable.
    • They are simple to prevent. The API will state whether or not null is a possible result of the API method. If the method can return null, you need to:
      • Store the returned value in a variable.
      • Null check that variable. If not null, you can perform actions upon it.
      • Null checking is like so: if (variable == null) //Oh no. The variable is null. Let's not perform any action upon it.
      • Note: theMethod() != theMethod()
        • Values returned by methods may not always be the same. The first could be not null, and the second could be null.
        • Do not null check the return of a method unless you store that returned value in a variable, then null check that variable.
        • Example:
        •  
          if (object.getDefinition() != null) {
           final String name = object.getDefinition().getName();
          }

           

        • The first call to getDefinition() may not result in a null returned value, and would pass the null check. The second call to getDefinition() could return null, resulting in an NPE. In this case, the returned value of getDefinition() should be stored in a variable. That variable should then be null checked. After the null check is passed, getName() can be called upon that variable.
  • IndexOutOfBoundsException
    • This occurs when you try to load an element from an array which is not within the bounds of the array. This exception is thrown when an array element is loaded from from index such that:
      • index < 0
      • index >= array.length
    • Always make sure to check the length of the array before trying to grab an array element at an index. Also, never try grabbing an array element at a negative index. Negative indices don't exist.
    • Index checking is simple:
      •  
        if (index >= 0 && index < array.length) {	//The index is within the bounds of the array.
                                                    //We can pull the value of array[index] now.
        }

         

      • Sometimes checking index >= 0 isn't necessary if you already know index isn't negative.
  • Infinite Loops
    • Infinite loops occur when a thread never exits a loop. Typically, these are while loops. Make sure to use a timeout on loops to prevent this.
  • Inefficient Coding
    • There exists so many possibilities which inefficient code can exist. I'll give just a few pointers:
      • In while loops (sometimes also other types of loops), make sure to include a sleep at the top of the loop. If the loop contains no sleeps, it will execute the code of the loop as much as possible, and as fast as possible. The loop will use as much CPU power as it is able to. Avoid this.
      • Store returned values from methods in variable if you are going to use the value twice. You may already need to store the value in a variable to do a null check anyways.
      • If you are waiting for a condition, make sure to use appropriate sleeps.
        • If you don't need to perform an action immediately after a different action, or if a few hundred milliseconds doesn't harm the outcome of whatever you are doing, use a larger sleep rather than a smaller one. Larger waits will reduce CPU usage.
      • When using object finding, doing set the tile radius too large. If an object is expected to be within 10-20 tiles of your character, don't search for the object with a radius of 60 (unless there is a reason to).
      • Don't define all the needed variables of a method all at once. Define them one at a time, then inspect the variable. You may not need to use all of the variable before coming to a conclusion.

7. Bug Fixing

  • A lot of scripters here haven't quite yet grasped the concept of bug finding and fixing, so here we go.
  • First, you have to identify the problem. Let's create an example... the script isn't clicking on the oven (cooking script).
  • Next, you have to identify the code that is responsible for performing the action which isn't being performed. In our example, we have to find the piece of code that clicks the oven.
  • Next, try doing a brief scan of your code and see if you can find any obvious logic errors.
  • If weren't able to solve the bug with a brief scan, then try debugging code. Here's what I suggest: using println. Use println to determine if a section of code is being executed or not. If it's not being executed, try to find where the execution cuts off. Find the exact position where the execution cuts off.
    • This cut off will likely help you fix the bug. Identify why the execution cuts off at where it does, then fix it.
  • You will probably also have to check variables. Check all variables, and all method return values in suspect. The way you check variable is you println their value(s).
  • In our example, we should have inserted printlns to make sure our oven clicking method was being hit, and we should have checked the variables involved in clicking the oven.
  • That's the gist of bug fixing. Think about what is going wrong, what code is responsible, and why the code is failing. Println everything.

8. Conclusion

  • That concludes this scripting tutorial for now. I may expand it in the future. Warning: I may or may not respond to individual scripting questions on this thread.

Here is the final script from this tutorial:

 

package scripts;
import org.tribot.api.DynamicClicking;
import org.tribot.api.General;
import org.tribot.api.Timing;
import org.tribot.api.types.generic.Condition;
import org.tribot.api2007.Banking;
import org.tribot.api2007.Inventory;
import org.tribot.api2007.NPCs;
import org.tribot.api2007.Objects;
import org.tribot.api2007.Player;
import org.tribot.api2007.Walking;
import org.tribot.api2007.WebWalking;
import org.tribot.api2007.types.RSNPC;
import org.tribot.api2007.types.RSObject;
import org.tribot.api2007.types.RSTile;
import org.tribot.script.Script;

public class TutorialScript extends Script {

	private RSTile last_tree_tile = null;

	/**	 
	 * Checks if we are at the trees.
	 * 	
	 * @return True if we are at the trees; false otherwise.	
	 */
	private boolean isAtTrees() {
		// We search for the trees by their name - Willow. The means that we	
		// will search for the trees within a radius of 20 tiles from our	
		// character. If they are more than 20 tiles away, the findNearest
		// method will not find them. Although, if they are more than 20 tiles
		// away, we can be sure that they aren't on the screen.	
		// We will now store the variable returned form findNearest in the	
		// variable called 'willows'. We declare this variable final because we	
		// will not be changing it's contents after the variable is set.
		// According to the API, the returned value from findNearest will be
		// RSObject[]. If there are no trees found, the array will not contain
		// any elements. The returned value cannot be null, and therefore we
		// don't have to null check it.		
		// Next, we check the length of the array. If the length is less than 1,	
		// we know that no trees were found. We can now return false.
		final RSObject[] willows = Objects.findNearest(20, "Willow");
		if (willows.length < 1)
			return false;
		// The array contains at least one element. The first element in the
		// array will be the nearest tree to our character. Let's check if this
		// tree is on screen. We will return the value.	
		return willows[0].isOnScreen();
	}

	/**	 
	 * Checks if we are in the bank.	
	 * 	
	 * @return True if we are in the bank; false otherwise.	
	 */
	private boolean isInBank() {
		// Let's first search for on-screen booths.	
		final RSObject[] booths = Objects.findNearest(20, "Bank booth");
		if (booths.length > 1) { // A booth is in the array. Let's check if the first element of the		
			// array is on the screen.		
			if (booths[0].isOnScreen())
				return true;
			// The booth is on the screen. We don't need to
			// check for visible bankers since we already know	
			// that we are in the bank. Let's exit this method	
			// and return true.			
		}

		// Nope, the nearest booth is no visible. Let's go and and search	
		// for bankers.		
		final RSNPC[] bankers = NPCs.findNearest("Banker");
		if (bankers.length < 1)
			return false; // No booths are on the screen, and no bankers exist.	
		// Let's just exit already since we know that we are		
		// not in the bank. We will return false.	

		// Okay, so we found a banker. The first element in the array is the	
		// nearest NPC. Let's check if that NPC is on-screen.	
		return bankers[0].isOnScreen(); // Return whether or not the banker is on	
		// the screen. If it is, we are in the			
		// bank; if not, then we are not in the		
		// bank.
	}

	/**	 
	 * Attempts to cut a tree. If we are already cutting a tree, we will wait	 
	 * until that tree has been cut.	 
	 * 	 
	 * @return True if we were able to cut the tree; false otherwise.	 
	 */
	private boolean cut() {
		if (isCutting()) {
			final long timeout = System.currentTimeMillis() + General.random(60000, 90000); // Let's define a timeout for the loop below. If we don't have a
			// timeout, it is possible that the script will enter an infinite
			// loop, and will therefore be stuck. We set the timeout for the
			// current time plus somewhere between 60 and 90 seconds. We use
			// randomness to avoid seeming bot-like.
			while (isCutting() && System.currentTimeMillis() < timeout) {
				sleep(100, 150); // We will loop while we are cutting, and while the current time			
				// is before the timeout. Make sure to have a sleep to prevent a				// CPU overload.				
				// We could also implement some anti-ban features here if we	
				// want.			
				// Now, let's check if the willow tree is still at the location	
				// of the last clicked location. To do this, we will define a	
				// global variable - last_tree_tile - of type RSTile. The	
				// variable will be defined below, when we find and click a	
				// tree.			
				// Make sure to null check the variable, since it can be null.
				// If it is null and we try to perform actions upon it, a Null	
				// Pointer Exception will be thrown, crashing the script.	
				if (this.last_tree_tile != null) {
					// The variable is not null. We can use it now.			
					if (!Objects.isAt(this.last_tree_tile, "Willow")) {
						// The willow tree is gone. It has either been chopped		
						// down, or turned into an ent. Let's break out of this		
						// loop.	
						break; // Good-bye loop	
					}
				}
			}
		}
		// Let's go find a tree to chop.
		final RSObject[] trees = Objects.findNearest(50, "Willow");
		// Search for the willow within 50	tiles
		// from our character.		
		if (trees.length < 1)
			return false; // No trees have been found. We can't do anything, so	
		// let's exit this method.

		if (!trees[0].isOnScreen()) {
			// The nearest tree is not on the screen. Let's walk to it.	
			if (!Walking.walkPath(Walking.generateStraightPath(trees[0]))) // We could not walk to the tree. Let's exit so we don't try	
				// clicking a tree which isn't on screen.
				return false;

			if (!Timing.waitCondition(new Condition() { // We will now use the Timing API to wait until the tree is on	
				// the screen (we are probably walking to the tree right now).	
				@Override
				public boolean active() {
					General.sleep(100); // Sleep to reduce CPU usage.
					return trees[0].isOnScreen();
				}
			}, General.random(8000, 9300)))
				// A tree could not be found before the timeout of 8-9.3	
				// seconds. Let's exit the method and return false. we don't		
				// want to end up trying to click a tree which isn't on the
				// screen.		
				return false;
		}
		// Okay, now we are sure trees[0] is on-screen. Let's click it. We may	
		// be still moving at this moment, so let's use DynamicClicking.		
		// DynamicClicking should be used when your character is moving, or the	
		// target is moving, and you need to click the target.	
		if (!DynamicClicking.clickRSObject(trees[0], "Chop down")) // We could not click the tree. Let's exit the method since we		
			// failed.
			return false;
		// We clicked the tree. Let's first wait to stop chopping for 1-1.2	
		// seconds just in case we moved on to this tree while still performing		
		// the chopping animation.	
		Timing.waitCondition(new Condition() {
			@Override
			public boolean active() {
				return !isCutting();
			}
		}, General.random(1000, 1200));
		// We don't need to if check it since the result doesn't matter.		
		if (Timing.waitCondition(new Condition() {
			// Now let's wait until we are cutting.			
			@Override
			public boolean active() {
				return isCutting();
			}
		}, General.random(8000, 9000))) {
			// We are cutting! Now let's record the tree's tile and return true.			
			this.last_tree_tile = trees[0].getPosition().clone(); // getPosition() can never be null, so we don't need to null check		
			// it.		
			return true;
		}
		// We failed to cut a tree. Return false.	
		return false;
	}

	/**	 
	 * Checks if we are cutting a tree.	
	 * 	 
	 * @return True if were are cutting a tree; false otherwise.	
	 */
	private boolean isCutting() {
		return Player.getAnimation() > 0; // If the animation ID is greater than			
		// 0, then we are animating. Let's		
		// assume that if were are							
		// animating, that the animation is		
		// the chopping one.	
	}

	/**	 
	 * Attempts to walk to the bank.	
	 * 	 
	 * @return True if we were able to walk to the bank; false otherwise.	 
	 */
	private boolean walkToBank() {
		if (!WebWalking.walkToBank()) { // We failed to walk to the bank. Let's return false.	
			return false;
		}
		// Walking succeeded, but we may still be moving, and not our destination	
		// yet. Let's wait until we are in the bank.	
		return Timing.waitCondition(new Condition() { // If we reach the bank before the timeout, this method will return		
			// true. Otherwise, it will return false.			
			@Override public boolean active() {
				General.sleep(200, 300); // Reduces CPU usage.		
				return isInBank();
			}
		}, General.random(8000, 9000));
	}

	/**	
	 * Attempts to walk to the trees.	
	 * 	
	 * @return True if we were able to walk to the trees; false otherwise.
	 */
	private boolean walkToTrees() {
		final RSObject[] willows = Objects.findNearest(50, "Willow");
		if (willows.length < 1) // No willows could be found. We cannot do anything. Let's exit this		
			// method.		
			return false;
		// Let's walk to the closest willow tree now.	
		if (!WebWalking.walkTo(willows[0]))
			// We failed to walk to the bank. Let's return false.	
			return false;
		// Walking failed, but we may still be moving, and not our destination	
		// yet. Let's wait until we are at the trees.		
		return Timing.waitCondition(new Condition() { // If we reach the trees before the timeout, this method will return	
			// true. Otherwise, it will return false.	
			@Override public boolean active() {
				General.sleep(200, 300); // Reduces CPU usage.	
				return isAtTrees();
			}
		}, General.random(8000, 9000));
	}

	/**	 
	 * Attempts to bank our items.
	 * 	
	 * @return True if we were successfully able to bank the items;
	 * false otherwise.         
	 */
	private boolean bank() {
		if (!Banking.isBankScreenOpen()) { // The bank screen is not open. Let's open it.		
			if (!Banking.openBank())
				// Could not open the bank. Let's return false.		
				return false;
			// Since openBank() will wait for the bank screen to be open before	
			// returning true, it is safe to assume that the bank screen is now		
			// open.		
		}
		// Now let's deposit the logs. We will check if an axe is in our	
		// inventory. If there is one, we will bank by using our inventory	
		// items. Otherwise, we will just click the deposit all button.	
		// Let's define our axe names now. It is better to define variables like	
		// this globally, but we only use the axe names within this method, so I	
		// don't feel the need to.		
		final String[] axe_names = {
				"Bronze axe",
				"Iron Axe",
				"Black Axe",
				"Steel Axe",
				"Mithril Axe",
				"Adamant Axe",
				"Rune Axe",
				"Dragon Axe"
		};
		if (Inventory.find(axe_names).length > 0) { // If the length of the returned value if greater than one, that		
			// means we have an axe in our inventory.	
			if (Banking.depositAllExcept(axe_names) < 1)
				// We failed to deposit our items. Let's exit and return false.		
				return false;
		} else {
			if (Banking.depositAll() < 1)
				// We failed to click the deposit all button. Let's exit and				// return false.	
				return false;
		}
		// Okay, our items should get deposited. Let's wait and make sure they
		// get deposited.		
		return Timing.waitCondition(new Condition() { // Since we can only enter the bank method if our inventory is full,	
			// let's wait until our inventory is not full. If it is not full	
			// before the timeout, return true. Otherwise, return false.		
			@Override
			public boolean active() {
				return !Inventory.isFull();
			}
		}, General.random(3000, 4000));
	}


	@Override
	public void run() {
		while (true) {
			sleep(50);
			if (isAtTrees()) { // We are at the trees		
				// Time to check what to do. If the inventory is full, we should	
				// walk to the bank. Otherwise, we should cut the willows.	
				if (Inventory.isFull()) { // The inventory is full	
					walkToBank(); // Let's walk to the bank			
				} else // The inventory is not full	
					cut(); // Let's cut the willows.	
			} else if (isInBank()) { // We are at the bank	
				// Time to check what to do. If the inventory is full, we should	
				// bank the items. Otherwise, we should walk back to the trees.		
				if (Inventory.isFull()) // The inventory is full		
					bank(); // Let's bank the items		
				else  // The inventory is not full	
					walkToTrees(); // Let's walk to the trees.		
			} else { // We are neither in the bank, nor at the willows		
				// Time to check what to do. If the inventory is full, we will	
				// walk to the bank. Otherwise, we will walk to the willows.	
				if (Inventory.isFull()) // Inventory is full		
					walkToBank(); // Walk to the bank			
				else // Inventory is not full		
					walkToTrees(); // Walk to the trees.	
			}
		}
	}
}
Edited by iFluffee
Forum Software update made all lines one lined. Attempted to fix it.
16 people like this

Share this post


Link to post
Share on other sites

Awesome post! anyone who were to read through all of this would have a good understanding on the structure and the api.

Share this post


Link to post
Share on other sites

Thank you so much, Read through the whole thing and followed along :). Helped me Greatly, Amazing Reference! Thanks!

Share this post


Link to post
Share on other sites

This is an awesome tutorial! Thank you very much for posting this. It has helped me gain a good understanding of how to use the methods as well as an insight to some of the problems I will run into when scripting.

Share this post


Link to post
Share on other sites

EDIT: Problem fixed. Had to add package scripts at the top. 

 

I have wrote some scripts for RSBot, and now I would like to write some for TriBot. 

I wrote this simple code just to check if i got the id`s right. But i cant even get it to load in TriBot.

Can anyone check what did i do wrong?

I copied the classes that i got from Eclipse into the "C:\Users\####\AppData\Roaming\.tribot\bin\scripts"

import java.awt.Graphics;import java.util.HashSet;import java.util.Set;import org.tribot.api.rs3.Backpack;import org.tribot.api.rs3.ScreenModels;import org.tribot.api.rs3.types.ScreenModel; import org.tribot.script.Script;import org.tribot.script.ScriptManifest;@ScriptManifest(authors = { "Pecka40" }, category = "Fishing", name = "BasicFisher")public class BasicFisher extends Script {	private abstract class Action {		public abstract boolean isValid();		public abstract void doAction();		public abstract String getStatus();		public abstract void paint(Graphics g);	}	private Set<Action> actionList = new HashSet<Action>();	private Action action;	@Override	public void run() {		setUp();		while (true) {			if (action != null) {				if (action.isValid()) {					action.doAction();				} else {					action = null;				}			} else {				for (Action i : actionList) {					if (i.isValid()) {						action = i;					}				}			}			sleep(100);		}	}	private void setUp() {		actionList.add(new Fish());	}	private class Fish extends Action {		long lureID = 4390934;		@Override		public boolean isValid() {			ScreenModel[] models = ScreenModels.findNearest(lureID);			if (!Backpack.isFull() && models.length > 0) {				return true;			}			return false;		}		@Override		public void doAction() {			ScreenModel[] models = ScreenModels.findNearest(lureID);			if (models.length > 0) {				models[0].click("Lure");			}		}		@Override		public String getStatus() {			return null;		}		@Override		public void paint(Graphics g) {		}	}}
Edited by Pecka40

Share this post


Link to post
Share on other sites

Great tutorial :)
Could you do some advanced tutorial also, please?

 

@TRiLeZ , could you help me with something? This part:

 

  • Now, let's fill in isAtTrees(). How should we do this? Let's find the nearest willow tree, and see if it is on-screen.

 

I have to make a new private .class for that? or where shall I start filling this commands? A bit confused.

 

Thanks in advance :D

Edited by podgorsek
1 person likes this

Share this post


Link to post
Share on other sites

@podgorsek

 

Read the comments trilez left in his code, it explains how he did that. All of his code is in one class, you can view his final result at the very end of his original post.

Share this post


Link to post
Share on other sites

@erickho123 thanks for extreme fast respond! :)

 

well, seems I'll just have to go through everything again. I came to the point, that really confused me, so my brain didn't recognize something my eyes stared to.

Oh and I missed the spoiler of final script.... lol

thanks again :D

Share this post


Link to post
Share on other sites

Hi, I got another problem.

When I go to my Java projects, inside "bin" folder, where it should be "podChopper.class", there are:

 

podChopper$1.class", "podChopper$2.class", "podChopper$3.class", "podChopper$4.class", "podChopper$5.class", "podChopper$6.class", "podChopper.class"

 

and none of them appears when I hit start script button on tribot (they are copied to correct folder 100%).

 

what am I doing wrong?

here is the sorce of the script: http://pastebin.com/edtPWq0J

it's just re-written, that makes it eaven wierder.

Share this post


Link to post
Share on other sites

Why not just make multiple class files instead of keeping it all in one file? I can't imagine scrolling through all this in one Class file.

 

- TKEgold

 

PS - Great post, this is perfect for young players interested in the computing field.

 

@TRiLeZ

Edited by TKEgold

Share this post


Link to post
Share on other sites

Can you post an Up To Date version?? Many things have changes in 2 years, lots of files and folders renamed. Cant manage to view my own scripts following 4 different tutorials all 2-3 years old.

Share this post


Link to post
Share on other sites

Hello, 

I'm new to the tribot scripting and I was wondering, once I have my Java class programmed how do I compile it and run it on Tribot for testing?

Thanks

Share this post


Link to post
Share on other sites

Thanks for this tutorial it was extremely helpful in learning the API. This bot works perfectly, now it's time to learn how to add in some anti-ban to it.

 

For those who are having trouble with errors: Please make sure you are using the current 2007 API. Using a method which is meant for EOC will give you an error.

Share this post


Link to post
Share on other sites

Where do I get the Import Script ? I am using NetBeans, pretty much the same thing as eclipse.

 

I want to get going on building but just cannot figure out where to get the import from.

Share this post


Link to post
Share on other sites

How do you import the org.tribot.scripts.Script at the beginning?

 

 

The TRiBot.jar needs to be setup as a dependency. What is your current development setup (Operating System and IDE)?

Share this post


Link to post
Share on other sites

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

  • Recently Browsing   0 members

    No registered users viewing this page.