Toma 43 Posted November 3, 2020 Share Posted November 3, 2020 1) Intro This is the first part of my Hill Giants tutorial script. The focus will be on making a working F2P hill giants script first, and then adding p2p functionalities (ex. potions). I will assume that you have successfully finished setting up your local script repository. If not, please go do that first. I will also assume that you have SOME experience in Java/programming. I won't be explaining every little detail. Create new project and set it up. I named it "GiantSlayer". First of all, further down the line, when you will creating scripts yourself, if you don't know how classes connect or if you wanna see if there's a certain method in the API, you can always look at the powbot api documentation - https://powbot.org/docs/ Also, there's a powbot discord where there's a lot of nice people that are ready to help you with any problem that you might have - https://discord.com/invite/aBG7YqtXeF So with that out of the way, lets start. 2) Creating a base class First, lets create a package. Right click "src" folder and create new package. I will name it "toma". Now right click on the new package/folder and create another package with the name of your script. I named it "giantslayer". Create new java class in that package and name it "GiantSlayer". You should have a new empty class. Lets extend our class with a custom powbot class PollingScript. PollingScript gives us a basic game loop through poll() method which is called every frame while the game is running. It also gives us access to ClientContext through a variable ctx. ClientContext is a class that gives us access to all of the API classes, pretty much everything we need to interact with the game; be it bank, inventory, skills, magic, npcs, etc. TIP: In IntelliJ , if you see that a class name or variable is colored red that probably means that you're missing an import or that you need to implement required methods. You can easily do that by hovering over said name and clicking "alt+enter", a context menu will open from which you can choose to import a missing class or implement methods. Add missing imports You can also add additional overridden method "public void start()". Override simply means that we're replacing or overriding the method that was defined in the parent class (PollingScript). Method start() is called only once when script is started, while poll() gets called every frame. Everything that needs to be defined when the script starts will be defined in start(). Ok, so now we have this. Before we continue lets also add Script.Manifest so we can actually run the script. Add the following code right before the class definition (under imports) @Script.Manifest( name = "GiantSlayer", description = "Kills Hill Giants", version = "0.0.1" ) Now lets create a basic attack and heal functionality. 3) Query API But first lets briefly touch upon the Query system of the powbot api. There's a few different queries but the general syntax is pretty much the same. The whole point is that every method that is done on the query will return the modified query. That means you can chain lots of methods on the same query, instead of calling them separately. So if we want to find the nearest npc with the name "Hill Giant" we would do this: ctx.npcs.select().name("Hill Giant").nearest().poll() - select() will refresh or rather repopulate the query (in our case with npcs) - name("Hill Giant") will remove every npc that doesn't contain that name - nearest() will sort npcs by distance to player - poll() gives you a head of the query (list) AND it will remove it (npc) from the query (list), so in our case it will be the closest Hill Giant npc (there's also peek(), which doesn't remove anything) Its important to note that the contents of query are persistent, they will not change until you call .select() again , not to be confused with select(Filter<k>), this one will not reset the query. Also, poll() and peek() will never return null. If the query is empty they will return empty entity. If you want to check if the returned entity is valid you should use entity.valid(), rather than null-checking. 4) Attack and heal functionality 4.1) Attack Alright, lets finally implement attack and heal. Create a new method private void attack() in GiantSlayer class. First, we need to actually find an npc to attack. For that we will of course use our query api. Find the closest npc, check if it's valid, and then attack, but lets also check if we are not already interacting with this npc. public void attack() { // First we find the npc Npc giant = ctx.npcs.select().name("Hill Giant").nearest().poll(); // Check if it's valid and we're not already attacking him if (giant.valid() && !giant.interacting().equals(ctx.players.local())) { giant.interact("Attack"); } } You might have to import the Npc class. You can now call attack() function in poll(). Compile + run the program. You should be able to see the script in File->Run. Alright, it's kinda working, but it spam clicks a bit too much before it gets into combat. Lets add a conditional sleep. It will return true if we're interacting with the npc. First number (450) says how long to wait before it calls the condition aka frequency ( in ms), and the second one is the number of tries ( 3 in our case). So it will wait for the maximum of 450x3 = 1350 ms = 1.35 seconds before it continues. public void attack() { // First we find the npc Npc giant = ctx.npcs.select().name("Hill Giant").nearest().poll(); // Check if it's valid and we're not already attacking him if (giant.valid() && !giant.interacting().equals(ctx.players.local())) { // Attack the giant giant.interact("Attack"); // Wait until we have started interacting Condition.wait(new Callable<Boolean>() { @Override public Boolean call() throws Exception { return giant.interacting().equals(ctx.players.local()); } },450,3); } } Ok, so now it's not spamming as much. Lets implement healing. 4.2) Heal Create a new fuction private void heal() Before you do anything else create a new int variable in the GiantSlayer class. We will need it for the food id. private final static int FOOD_ID = 361; 361 is the ID of "Tuna". To find item IDs you must have them in the inventory and then go to View->Items. Ok, now add this code to the function. We will also use Condition.wait(), but this time we will wait for script to click on the item, we can use it like that because food.interact() returns a boolean (true if clicked, false otherwise) private void heal() { // Find food in inventory Item food = ctx.inventory.select().id(FOOD_ID).poll(); // Wait until we have successfully clicked on the item Condition.wait(new Callable<Boolean>() { @Override public Boolean call() throws Exception { return food.interact("Eat"); } }, 350, 4); } 4.3) Combining heal and attack Now when we're done with the heal() function we can integrate everything together in the poll() function. First we check if we're out of food. If we are, stop the script. Then we check if health percentage is lower than some value (60% in this case). If it is, call heal() function, if not call attack() function. public void poll() { // First check if there's any food, if there's not, stop the script if (ctx.inventory.select().id(FOOD_ID).isEmpty()) { ctx.controller.stop(); } // If our health is under 60% we should heal if (ctx.players.local().healthPercent() <= 60) { heal(); } // Otherwise we can attack else { attack(); } } This is the final script. Now compile and run the script. It should now attack the nearest giant, switch to another one when the current one dies and heal when low on health. Congratulations if you have managed to successfully complete everything till now. This is gonna be it for this part. In the next part we will restructure our script in a better way, refine existing functionalities and add new ones. Thanks for reading. See you in the next part! 5 5 Quote Link to post Share on other sites
Argentavis 1 Posted December 25, 2020 Share Posted December 25, 2020 This is really useful information. I have always wanted to learn how to make some scripts. I don't care if I get accounts banned I just want to test out scripts and get it working. 1 Quote Link to post Share on other sites
JunkMale 3 Posted January 18 Share Posted January 18 Great info man, I haven't done a lick of programming in nearly 6 years but this was extremely helpful. Excited to get back into it. 1 Quote Link to post Share on other sites
Selirium 0 Posted Sunday at 06:08 PM Share Posted Sunday at 06:08 PM Hi Toma. I just got into scripting for PowerBot after viewing your post. I saw a couple of things didn't go right for initially with following this tutorial. It took a bit of searching but I seen that the Query API was deprecated after this tutorial was launched, and was superseded by Stream API. I got this code right now, in which I get the following error that I don't know how to fix: package Selirium.GoblinSlayer; import org.powerbot.script.PollingScript; import org.powerbot.script.Script; import org.powerbot.script.rt4.ClientContext; import org.powerbot.script.rt4.Npc; @Script.Manifest( name = "Goblin Slayer", description = "Slays Goblins", version = "0.0.1" ) public class GoblinSlayer extends PollingScript<ClientContext> { @Override public void start() { } @Override public void poll() { } public void attack() { // First we find the npc //Npc giant = ctx.npcs.select().name("Hill Giant").nearest().poll(); > Does not work anymore. Deprecated by Stream API. Npc goblin = ctx.npcs.toStream().within(4).name("Goblin").nearest().findFirst(); // Check if it's valid and we're not already attacking him if (goblin.valid() && !goblin.interacting().equals(ctx.players.local())) { goblin.interact("Attack"); } } } Error: Incompatible types. Found: 'java.util.Optional<org.powerbot.script.rt4.Npc>', required: 'org.powerbot.script.rt4.Npc' If I try the provided solution, which is to set the goblin variable to a "Optional<Npc>" variable, it cannot resolve the methods in line 34 (e.g. goblin.valid(), interacting() and interact()). Quote Link to post Share on other sites
Administrators const_ 31 Posted Sunday at 07:32 PM Administrators Share Posted Sunday at 07:32 PM 1 hour ago, Selirium said: Hi Toma. I just got into scripting for PowerBot after viewing your post. I saw a couple of things didn't go right for initially with following this tutorial. It took a bit of searching but I seen that the Query API was deprecated after this tutorial was launched, and was superseded by Stream API. I got this code right now, in which I get the following error that I don't know how to fix: package Selirium.GoblinSlayer; import org.powerbot.script.PollingScript; import org.powerbot.script.Script; import org.powerbot.script.rt4.ClientContext; import org.powerbot.script.rt4.Npc; @Script.Manifest( name = "Goblin Slayer", description = "Slays Goblins", version = "0.0.1" ) public class GoblinSlayer extends PollingScript<ClientContext> { @Override public void start() { } @Override public void poll() { } public void attack() { // First we find the npc //Npc giant = ctx.npcs.select().name("Hill Giant").nearest().poll(); > Does not work anymore. Deprecated by Stream API. Npc goblin = ctx.npcs.toStream().within(4).name("Goblin").nearest().findFirst(); // Check if it's valid and we're not already attacking him if (goblin.valid() && !goblin.interacting().equals(ctx.players.local())) { goblin.interact("Attack"); } } } Error: Incompatible types. Found: 'java.util.Optional<org.powerbot.script.rt4.Npc>', required: 'org.powerbot.script.rt4.Npc' If I try the provided solution, which is to set the goblin variable to a "Optional<Npc>" variable, it cannot resolve the methods in line 34 (e.g. goblin.valid(), interacting() and interact()). Npc goblin = ctx.npcs.toStream().within(4).name("Goblin").nearest().first(); Will give you what you want. 1 Quote Link to post Share on other sites
Toma 43 Posted Sunday at 09:32 PM Author Share Posted Sunday at 09:32 PM I will update the guide in the coming week. 2 Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.