Making A Basic Woodcutting Script
Prerequisites
- An IDE of your choice. In this guide I will be using IntelliJ IDEA, if you need help with setting up a development environment using IntelliJ IDEA you can visit Setting Up Your Development Environment.
- A clean project that contains your script's Main class, if you need help with setting up your first script, you can visit Running Your First Script then proceed with this guide.
Useful Links
Explv's Map will be using this site to make our "areas" in this guide.
Imgur will be used to upload our script image once we're done.
What you will create from this guide
This guide will show you how to create a simple woodcutting script that will chop trees till the inventory is full travel to a bank, bank logs, and repeat.
How we will handle certain conditions in our script
When making a script that does multiple different tasks, you're going to want to create conditions that change the state, and depending on the current state of the script make it perform a series of actions till another condition is met changing the current state.
We will do this by creating an Enum class and having our states inside that. Inside IntelliJ IDEA locate your projects src -> Right click -> New -> Java Class a small window will appear be sure to click Enum and name your class 'State'. Inside this class we're going to want the different states the bot will have, we will put the following;
-
FINDING_TREE - This state will be triggered if we are not chopping a tree and our inventory is not full
-
CHOPPING_TREE - This state will be triggered if we are chopping the tree
-
WALKING_TO_BANK - This state will be triggered if our inventory is full and we are not in the 'banking' area
-
BANKING - This state will be triggered when the Bank interface is open
-
USEBANK - This state will be triggered once we are inside the bank area.
-
WALKING_TO_TREES - This state will be triggered if out inventory isn't full and we are not inside the 'tree' area
Your class should look like the following;
We should also create a method within our main class that returns our State to use within a switch statement;
Writing the code to handle walking to the bank
Firstly, we are going to want to pick an area where we want to bank our logs, I am picking Varrock West Bank the coords for this area is as follows;
Area bankArea = new Area(3179, 3448, 3191, 3432);
Next we can work on the code that handles the condition that needs to be met to return the state to walk to the bank. In this if statement we are checking that our inventory is full and we are not inside the bank area, if this condition is met return state WALKING_TO_BANK.
private State getState() {
if (Inventory.isFull() && !bankArea.contains(Players.getLocal().getTile())) {
return State.WALKING_TO_BANK;
}
return state;
}
Let's go to our loop in our main class and make a switch statement and make a case with state WALKING_TO_BANK, inside this case we are going to want to check if our local player is moving, if we aren't moving we get a random tile that is inside the bankArea and click it.
switch(getState()) {
case WALKING_TO_BANK:
if (!Players.getLocal().isMoving()) {
Walking.walk(bankArea.getRandomTile());
}
break;
}
Your script should look like the following;
@ScriptManifest(name = "", description = "", author = "",
version = 1.0, category = Category.WOODCUTTING, image = "")
public class TestScript extends AbstractScript {
State state;
Area bankArea = new Area(3179, 3448, 3191, 3432);
@Override
public int onLoop() {
switch (getState()) {
case WALKING_TO_BANK:
if (!Players.getLocal().isMoving()) {
Walking.walk(bankArea.getRandomTile());
}
break;
}
return 1;
}
private State getState() {
if (Inventory.isFull() && !bankArea.contains(Players.getLocal().getTile())) {
return State.WALKING_TO_BANK;
}
return state;
}
}
Writing the code to handle opening bank and depositing items
Interacting With The Bank Booth
Now we are inside the bank area we are going to want to write the code that is firstly going to interact with a bank booth and then deposit our logs and close the bank interface.
Let's start with interacting with the bank. We will need to create a else if statement inside the getState method that will return State USEBANK when a condition is met, this condition will be if the inventory is full and our local player is inside the bankArea then return state USEBANK.
else if (Inventory.isFull() && bankArea.contains(Players.getLocal().getTile())) {
return State.USEBANK;
}
Now let's go back to our loop and add the logic for opening the bank, let's create a new case inside out switch statement with the state USEBANK, inside this case we are going to want to check 1 is the player currently moving? 2 is the bank interface open? if both are false then we will find the closest object to our local player that has the name "bank booth" and isn't null, we will interact with that object using "bank" We will sleep our the script till the bank interface is open or if 4 seconds elapse.
case USEBANK:
if (!Bank.isOpen() || !Players.getLocal().isMoving()) {
GameObject bankBooth = GameObjects.closest("Bank booth");
bankBooth.interact("Bank");
Sleep.sleepUntil(() -> Bank.isOpen(), 4000);
}
Your script should look like the following;
@ScriptManifest(name = "", description = "", author = "",
version = 1.0, category = Category.WOODCUTTING, image = "")
public class TestScript extends AbstractScript {
State state;
Area bankArea = new Area(3179, 3448, 3191, 3432);
@Override
public int onLoop() {
switch (getState()) {
case WALKING_TO_BANK:
if (!Players.getLocal().isMoving()) {
Walking.walk(bankArea.getRandomTile());
}
break;
case USEBANK:
if (!Bank.isOpen() || !Players.getLocal().isMoving()) {
GameObject bankBooth = GameObjects.closest("Bank booth");
bankBooth.interact("Bank");
Sleep.sleepUntil(() -> Bank.isOpen(), 4000);
}
break;
}
return 1;
}
private State getState() {
if (Inventory.isFull() && !bankArea.contains(Players.getLocal().getTile())) {
return State.WALKING_TO_BANK;
} else if (Inventory.isFull() && bankArea.contains(Players.getLocal().getTile())) {
return State.USEBANK;
}
return state;
}
}
Depositing Item Into The Bank
Now we have our bank interface open we are going to want to deposit out logs and close the bank window.
Let's start with our method that returns the state. This time we are going to want to check that the bank is open and the inventory is full and if both are true return BANKING
else if (Bank.isOpen() && Inventory.isFull()) {
return State.BANKING;
}
Now let's head to our loop again to add the logic for depositing logs into the bank and closing the bank interface, we can use Bank#depositAll here we can use an item name or an id, for this example I will use the item name, we need sleep the script till the inventory doesn't contain log or 2 seconds elapses we have a nest if statement that also checks to make sure the inventory doesn't contain logs and if it doesn't close the bank.
case BANKING:
Bank.depositAll("Logs");
Sleep.sleepUntil(() -> !Inventory.contains("Logs"), 2000);
if (!Inventory.contains("Logs")) {
Bank.close();
}
break;
Your script should look like the following;
@ScriptManifest(name = "", description = "", author = "",
version = 1.0, category = Category.WOODCUTTING, image = "")
public class TestScript extends AbstractScript {
State state;
Area bankArea = new Area(3179, 3448, 3191, 3432);
@Override
public int onLoop() {
switch (getState()) {
case WALKING_TO_BANK:
if (!Players.getLocal().isMoving()) {
Walking.walk(bankArea.getRandomTile());
}
break;
case USEBANK:
if (!Bank.isOpen() || !Players.getLocal().isMoving()) {
GameObject bankBooth = GameObjects.closest("Bank booth");
bankBooth.interact("Bank");
Sleep.sleepUntil(() -> Bank.isOpen(), 4000);
}
break;
case BANKING:
Bank.depositAll("Logs");
Sleep.sleepUntil(() -> !Inventory.contains("Logs"), 2000);
if (!Inventory.contains("Logs")) {
Bank.close();
}
break;
}
return 1;
}
private State getState() {
if (Inventory.isFull() && !bankArea.contains(Players.getLocal().getTile())) {
return State.WALKING_TO_BANK;
} else if (Inventory.isFull() && bankArea.contains(Players.getLocal().getTile())) {
return State.USEBANK;
} else if (Bank.isOpen() && Inventory.isFull()) {
return State.BANKING;
}
return state;
}
}
Walking Back To The Tree Area
If we don't have a full inventory and we aren't in the woodcutting area we are going to want to move our local player to the area to cut the trees in this example I am going to use the tree south of the grand exchange. There's a good chunk of trees there and it's close to both the grand exchange and the Varrock west bank.
Area normalTreeArea = new Area(3149, 3465, 3171, 3449);
Let's go back to out get state method and create the condition that once met will return WALK_TO_TREES, this time we are going to want to check to make sure our inventory isn't full and we are not in the tree area the code for that looks like the following;
else if (!Inventory.isFull() && !normalTreeArea.contains(Players.getLocal().getTile())) {
return State.WALKING_TO_TREES;
}
Next let's head back to our loop again and add the logic for this state, what we are going to do is create a new case called walking_to_tree, and inside that case we are going to want to check is our player isn't moving and if we're not get a random tile inside the tree area, keep repeating till our player is inside the tree area;
case WALKING_TO_TREES:
if (!Players.getLocal().isMoving()) {
Walking.walk(normalTreeArea.getRandomTile());
}
break;
After adding that code your script should look like the following;
@ScriptManifest(name = "", description = "", author = "",
version = 1.0, category = Category.WOODCUTTING, image = "")
public class TestScript extends AbstractScript {
State state;
Area bankArea = new Area(3179, 3448, 3191, 3432);
Area normalTreeArea = new Area(3149, 3465, 3171, 3449);
@Override
public int onLoop() {
switch (getState()) {
case WALKING_TO_BANK:
if (!Players.getLocal().isMoving()) {
Walking.walk(bankArea.getRandomTile());
}
break;
case USEBANK:
if (!Bank.isOpen() || !Players.getLocal().isMoving()) {
GameObject bankBooth = GameObjects.closest(b -> b != null && b.getName().equalsIgnoreCase("Bank booth"));
bankBooth.interact("Bank");
Sleep.sleepUntil(() -> Bank.isOpen(), 4000);
}
break;
case BANKING:
Bank.depositAll("Logs");
Sleep.sleepUntil(() -> !Inventory.contains("Logs"), 2000);
if (!Inventory.contains("Logs")) {
Bank.close();
}
break;
case WALKING_TO_TREES:
if (!Players.getLocal().isMoving()) {
Walking.walk(normalTreeArea.getRandomTile());
}
break;
}
return 1;
}
private State getState() {
if (Inventory.isFull() && !bankArea.contains(Players.getLocal().getTile())) {
return State.WALKING_TO_BANK;
} else if (Inventory.isFull() && bankArea.contains(Players.getLocal().getTile())) {
return State.USEBANK;
} else if (Bank.isOpen() && Inventory.isFull()) {
return State.BANKING;
} else if (!Inventory.isFull() && !normalTreeArea.contains(Players.getLocal().getTile())) {
return State.WALKING_TO_TREES;
}
return state;
}
}
Finding And Chopping Trees
In this last section we are going to want to write the code that would handle finding a target tree and interacting with that target tree, let's make the condition and logic from a target tree and interact with it. We're are going to want to check to make sure our inventory isn't full,
else if (!Inventory.isFull() && !Players.getLocal().isAnimating() && normalTreeArea.contains(Players.getLocal().getTile())) {
return State.FINDING_TREE;
}
Next, let's go back to our loop and create another case with FINDING_TREE inside that case we are going to want to check to make sure our player isn't moving to the tree or our player isn't already chopping the tree also as a precaution we're going to want to check to make sure that the target tree is inside the treeArea that can be done with the following code;
case FINDING_TREE:
if (!Players.getLocal().isAnimating() && !Players.getLocal().isMoving()) {
GameObject normalTree = GameObjects.closest(t -> t.getName().equalsIgnoreCase("tree") && normalTreeArea.contains(t.getTile()));
if (normalTree != null && normalTree.interact("Chop down")) {
Sleep.sleepUntil(() -> Players.getLocal().isAnimating(), 4000);
}
}
break;
The last bit of code we are going to want to check to see if we are chopping the tree, this state doesn't need logic because we're just making sure the state isn't null or returning the state that finds the tree, you are still able to go to your loop create a case inside that for CHOPPING_TREE and add some login there that can do randomized actions.
else if (!Inventory.isFull() && Players.getLocal().isAnimating() && normalTreeArea.contains(Players.getLocal().getTile())) {
return State.CHOPPING_TREE;
}
Your script should look like the following;
@ScriptManifest(name = "", description = "", author = "",
version = 1.0, category = Category.WOODCUTTING, image = "")
public class TestScript extends AbstractScript {
State state;
Area bankArea = new Area(3179, 3448, 3191, 3432);
Area normalTreeArea = new Area(3149, 3465, 3171, 3449);
@Override
public int onLoop() {
switch (getState()) {
case WALKING_TO_BANK:
if (!Players.getLocal().isMoving()) {
Walking.walk(bankArea.getRandomTile());
}
break;
case USEBANK:
if (!Bank.isOpen() || !Players.getLocal().isMoving()) {
GameObject bankBooth = GameObjects.closest("Bank booth");
bankBooth.interact("Bank");
Sleep.sleepUntil(() -> Bank.isOpen(), 4000);
}
break;
case BANKING:
Bank.depositAll("Logs");
Sleep.sleepUntil(() -> !Inventory.contains("Logs"), 2000);
if (!Inventory.contains("Logs")) {
Bank.close();
}
break;
case WALKING_TO_TREES:
if (!Players.getLocal().isMoving()) {
Walking.walk(normalTreeArea.getRandomTile());
}
break;
case FINDING_TREE:
if (!Players.getLocal().isAnimating() && !Players.getLocal().isMoving()) {
GameObject normalTree = GameObjects.closest(t -> t.getName().equalsIgnoreCase("tree") && normalTreeArea.contains(t.getTile()));
if (normalTree != null && normalTree.interact("Chop down")) {
Sleep.sleepUntil(() -> Players.getLocal().isAnimating(), 4000);
}
}
break;
case CHOPPING_TREE:
//you can set your state here if you want to display your current state to a GUI or perform random actions
break;
}
return 1;
}
private State getState() {
if (Inventory.isFull() && !bankArea.contains(Players.getLocal().getTile())) {
return State.WALKING_TO_BANK;
} else if (Inventory.isFull() && bankArea.contains(Players.getLocal().getTile()) && !Bank.isOpen()) {
return State.USEBANK;
} else if (Bank.isOpen() && Inventory.isFull()){
return State.BANKING;
} else if (!Inventory.isFull() && !normalTreeArea.contains(Players.getLocal().getTile())) {
return State.WALKING_TO_TREES;
} else if (!Inventory.isFull() && !Players.getLocal().isAnimating() && normalTreeArea.contains(Players.getLocal().getTile())) {
return State.FINDING_TREE;
} else if (!Inventory.isFull() && Players.getLocal().isAnimating() && normalTreeArea.contains(Players.getLocal().getTile())) {
return State.CHOPPING_TREE;
}
return state;
}
}
Be sure to name your script, a description and give yourself credit and make yourself an image:
Info
Your image should be uploaded to Imgur
@ScriptManifest(name = "Simple Choppa", description = "A simple script to chop trees south of the G.E and bank at Varrock west bank.", author = "JohnDoe2023",
version = 1.0, category = Category.WOODCUTTING, image = "https://i.imgur.com/ToBgn5h.png")