March 3, 201510 yr OSBot community, This is my first bot script. I would like to thank Pug and Apaec. I followed your tutorials and learned from them. I used that knowledge to create this script that is probably badly coded, but I'm learning and I want to learn more. Here it goes: Script Name: MGFighter: Melee Features: Picks up and buries bones Attacks NPCs (Currently only one and it is hardcoded in. I don't know how to add options and stuff like that through a menu) How long it has been running for In-Game Paint As stated through the title of the script, this is meant to be only for melee. The reason stands behind the paint. It shows levels gained as well as XP gained per different combat and I could only fit melee ones along side prayer on there. I would really enjoy any criticism. If you have feedback about my code, I am all eyes and ears. There is always room to learn and I would like to become a great script developer. Thank you, Rutsy ---------------------------------------------------------- Here is my source code: package osBotFightScript; import org.osbot.rs07.api.model.GroundItem; import org.osbot.rs07.api.model.Item; import org.osbot.rs07.api.model.NPC; import org.osbot.rs07.api.ui.Skill; import org.osbot.rs07.script.Script; import org.osbot.rs07.script.ScriptManifest; import java.io.IOException; import java.net.URL; import java.util.concurrent.TimeUnit; import java.awt.*; import javax.imageio.ImageIO; @ScriptManifest(author = "Rutsy", info = "A Basic Melee Training Script.", name = "MGFighter: Melee", version = 0.1, logo = "") public class main extends Script { private long timeBegan; private long timeRan; private int beginningXPAttack; private int beginningXPStrength; private int beginningXPDefence; private int beginningXPHitpoints; private int beginningXPPrayer; private int currentXPAttack; private int currentXPStrength; private int currentXPDefence; private int currentXPHitpoints; private int currentXPPrayer; private int xpGainedAttack; private int xpGainedDefence; private int xpGainedStrength; private int xpGainedHitpoints; private int xpGainedPrayer; private int currentLevelAttack; private int currentLevelDefence; private int currentLevelStrength; private int currentLevelHitpoints; private int currentLevelPrayer; private int beginningLevelAttack; private int beginningLevelDefence; private int beginningLevelStrength; private int beginningLevelHitpoints; private int beginningLevelPrayer; private int levelsGainedAttack; private int levelsGainedDefence; private int levelsGainedStrength; private int levelsGainedHitpoints; private int levelsGainedPrayer; private final Image bg = getImage("http://s27.postimg.org/8pkfefqjn/mgfighter_Background.png"); //Image loading from PUG private Image getImage(String url) { try { return ImageIO.read(new URL(url)); } catch (IOException e) {} return null; } @Override public void onStart() { log("Welcome to MGFighter: Melee ~ By Rutsy!"); timeBegan = System.currentTimeMillis(); beginningXPAttack = skills.getExperience(Skill.ATTACK); beginningXPStrength = skills.getExperience(Skill.STRENGTH); beginningXPDefence = skills.getExperience(Skill.DEFENCE); beginningXPHitpoints = skills.getExperience(Skill.HITPOINTS); beginningXPPrayer = skills.getExperience(Skill.PRAYER); beginningLevelAttack = skills.getStatic(Skill.ATTACK); beginningLevelStrength = skills.getStatic(Skill.STRENGTH); beginningLevelDefence = skills.getStatic(Skill.DEFENCE); beginningLevelHitpoints = skills.getStatic(Skill.HITPOINTS); beginningLevelPrayer = skills.getStatic(Skill.PRAYER); } private enum State { KILL, WAIT, PICKUP, BURY }; private State getState() { NPC goblin = npcs.closest("Goblin"); GroundItem bones = groundItems.closest("Bones"); if (goblin != null && !myPlayer().isAnimating() && !goblin.isUnderAttack()) return State.KILL; if (bones != null && !myPlayer().isUnderAttack()) return State.PICKUP; return State.WAIT; } @Override public int onLoop() throws InterruptedException { switch (getState()) { case PICKUP: GroundItem groundBones = groundItems.closest("Bones"); Item bones = inventory.getItem("Bones"); if ((!inventory.isFull() && !myPlayer().isUnderAttack())) { groundBones.interact("Take"); bones.interact("Bury"); sleep(random(300, 600)); } break; case KILL: NPC goblin = npcs.closest("Goblin"); if (goblin != null && !myPlayer().isAnimating() && !goblin.isUnderAttack()) { goblin.interact("Attack"); sleep(random(800, 1000)); } break; case WAIT: sleep(random(500, 700)); break; } return random(200, 300); } @Override public void onExit() { log("Thanks for running MGFighter: Melee!"); } @Override public void onPaint(Graphics2D g) { Graphics2D gr = g; //Background Image Loaded g.drawImage(bg, 2, 340, null); //Time Drawn on the Screen timeRan = System.currentTimeMillis() - this.timeBegan; g.drawString(ft(timeRan), 135, 404); //Drawing Numbers of the Screen currentXPAttack = skills.getExperience(Skill.ATTACK); xpGainedAttack = currentXPAttack - beginningXPAttack; currentLevelAttack = skills.getStatic(Skill.ATTACK); levelsGainedAttack = currentLevelAttack - beginningLevelAttack; g.drawString("" + xpGainedAttack + " (" + levelsGainedAttack + ")", 135, 435); currentXPDefence = skills.getExperience(Skill.DEFENCE); xpGainedDefence = currentXPDefence - beginningXPDefence; currentLevelDefence = skills.getStatic(Skill.DEFENCE); levelsGainedDefence = currentLevelDefence - beginningLevelDefence; g.drawString("" + xpGainedDefence + " (" + levelsGainedDefence + ")", 135, 467); currentXPStrength = skills.getExperience(Skill.STRENGTH); xpGainedStrength = currentXPStrength - beginningXPStrength; currentLevelStrength = skills.getStatic(Skill.STRENGTH); levelsGainedStrength = currentLevelStrength - beginningLevelStrength; g.drawString("" + xpGainedStrength + " (" + levelsGainedStrength + ")", 312, 467); currentXPHitpoints = skills.getExperience(Skill.HITPOINTS); xpGainedHitpoints = currentXPHitpoints - beginningXPHitpoints; currentLevelHitpoints = skills.getStatic(Skill.HITPOINTS); levelsGainedHitpoints = currentLevelHitpoints - beginningLevelHitpoints; g.drawString("" + xpGainedHitpoints + " (" + levelsGainedHitpoints + ")", 312, 435); currentXPPrayer = skills.getExperience(Skill.PRAYER); xpGainedPrayer = currentXPPrayer - beginningXPPrayer; currentLevelPrayer = skills.getStatic(Skill.PRAYER); levelsGainedPrayer = currentLevelPrayer - beginningLevelPrayer; g.drawString("" + xpGainedPrayer + " (" + levelsGainedPrayer + ")", 312, 404); } //Time conversion function from PUG private String ft(long duration) { String res = ""; long days = TimeUnit.MILLISECONDS.toDays(duration); long hours = TimeUnit.MILLISECONDS.toHours(duration) - TimeUnit.DAYS.toHours(TimeUnit.MILLISECONDS.toDays(duration)); long minutes = TimeUnit.MILLISECONDS.toMinutes(duration) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS .toHours(duration)); long seconds = TimeUnit.MILLISECONDS.toSeconds(duration) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS .toMinutes(duration)); if (days == 0) { res = (hours + ":" + minutes + ":" + seconds); } else { res = (days + ":" + hours + ":" + minutes + ":" + seconds); } return res; } } Here is a screenshot: http://imgur.com/adTGY3F If I could post images, it would have been easier. I apologize for having to click the image link. Edited March 3, 201510 yr by Rutsy
March 3, 201510 yr Yay! Congratulations on your first script! If you are interested, I can teach you how to implement a GUI to your script (GUI = Graphic User Interface (i.e menu basically, not paint!)). I'm glad you found my tutorial helpful, all you have to do now is stay interested, and the more you code, the more familiar you get with the API and general java concepts. Ofcouse, if you have any questions, please don't hesitate to ask me them via PM, i'd be willing to help. Apa
March 3, 201510 yr Author Yay! Congratulations on your first script! If you are interested, I can teach you how to implement a GUI to your script (GUI = Graphic User Interface (i.e menu basically, not paint!)). I'm glad you found my tutorial helpful, all you have to do now is stay interested, and the more you code, the more familiar you get with the API and general java concepts. Ofcouse, if you have any questions, please don't hesitate to ask me them via PM, i'd be willing to help. Apa Thank you very much. I am really looking forward to gaining some experience on script development. I actually am interested in learning about GUI implementation, and yes I guess I meant pain on the screen. I'll edit that. Thank you, Rutsy
March 3, 201510 yr I've seen a lot of scripts and I can tell you that this one is really clean / easy to read, especially for a first one! There are a few things that are redundant / could be more efficient but overall this is really nice Gratz!
March 3, 201510 yr Author I've seen a lot of scripts and I can tell you that this one is really clean / easy to read, especially for a first one! There are a few things that are redundant / could be more efficient but overall this is really nice Gratz! That is great to hear! I will keep practicing. Could you state what is redundant and how it can be more efficient? It'll help me make better scripts in the future. Thank you, Rutsy
March 3, 201510 yr That is great to hear! I will keep practicing. Could you state what is redundant and how it can be more efficient? It'll help me make better scripts in the future. Thank you, Rutsy Sure: 1. The WAIT state doesn't require a sleep, this just makes your script slower and less responsive which I wouldn't call desirable. I suggest you leave that state blank. Keep in mind every time the script loops it already sleeps for the onLoop()'s return value (in your case 200-300 ms). 2. Every time getState() is called you look for both the closest goblins and the closest bones. I suggest you look first for the goblin to check if the KILL state is valid. If the KILL state is not valid, then and only then look for the closest bones. Only try and get a value when that value is required. Like so: // mhm let's search the closest goblin to see if the KILL state is valid. NPC goblin = npcs.closest("Goblin"); if (goblin != null && !myPlayer().isAnimating() && !goblin.isUnderAttack()) return State.KILL; // if the code reaches this point it means the KILL state isn't valid. // what should I do next? mhm perhaps I should try and find the closest bones now. GroundItem bones = groundItems.closest("Bones"); if (bones != null && !myPlayer().isUnderAttack()) return State.PICKUP; 3. This one is also related to goblins and bones. I'm going to demonstrate the issue with the goblin case. In your getState() you scan all NPCs and try to get the closest goblin, you then store the value of that goblin locally and when the method has finished the value is discarded. Ok so a goblin was found, you are ready to kill but... you already forgot which one to kill (the previously locally stored value is already gone *sadface*). You rescan all NPCs again for the closest goblin and now you can finally attack it. That's two scans for one goblin. If you were to store the closest goblin found in the getState() method in a global value then you could just re-use that value in your onLoop(), boom: one goblin, one scan. 4. These are small errors, you are doing a great job and you might not even notice the difference when fixing these inefficiencies ;)
March 3, 201510 yr Author Sure: 1. The WAIT state doesn't require a sleep, this just makes your script slower and less responsive which I wouldn't call desirable. I suggest you leave that state blank. Keep in mind every time the script loops it already sleeps for the onLoop()'s return value (in your case 200-300 ms). 2. Every time getState() is called you look for both the closest goblins and the closest bones. I suggest you look first for the goblin to check if the KILL state is valid. If the KILL state is not valid, then and only then look for the closest bones. Only try and get a value when that value is required. Like so: // mhm let's search the closest goblin to see if the KILL state is valid. NPC goblin = npcs.closest("Goblin"); if (goblin != null && !myPlayer().isAnimating() && !goblin.isUnderAttack()) return State.KILL; // if the code reaches this point it means the KILL state isn't valid. // what should I do next? mhm perhaps I should try and find the closest bones now. GroundItem bones = groundItems.closest("Bones"); if (bones != null && !myPlayer().isUnderAttack()) return State.PICKUP; 3. This one is also related to goblins and bones. I'm going to demonstrate the issue with the goblin case. In your getState() you scan all NPCs and try to get the closest goblin, you then store the value of that goblin locally and when the method has finished the value is discarded. Ok so a goblin was found, you are ready to kill but... you already forgot which one to kill (the previously locally stored value is already gone *sadface*). You rescan all NPCs again for the closest goblin and now you can finally attack it. That's two scans for one goblin. If you were to store the closest goblin found in the getState() method in a global value then you could just re-use that value in your onLoop(), boom: one goblin, one scan. 4. These are small errors, you are doing a great job and you might not even notice the difference when fixing these inefficiencies I removed the sleep in the WAIT case. Could you teach me how to assign a global variable to the getState()'s goblin? Thank you, Rutsy
March 3, 201510 yr //IMPORTS public class main extends Script { private NPC one_goblin_per_scan; // GLOBAL GOBLIN VARIABLE private long timeBegan; private long timeRan; //... private State getState() { one_goblin_per_scan= npcs.closest("Goblin"); // STORE GOBLIN // ... } @Override public int onLoop() throws InterruptedException { switch (getState()) { //... case KILL: if (one_goblin_per_scan!= null && !myPlayer().isAnimating() && !(one_goblin_per_scan.isUnderAttack()) { (one_goblin_per_scan.interact("Attack"); sleep(random(800, 1000)); //... }
March 3, 201510 yr Author //IMPORTS public class main extends Script { private NPC one_goblin_per_scan; // GLOBAL GOBLIN VARIABLE private long timeBegan; private long timeRan; //... private State getState() { one_goblin_per_scan= npcs.closest("Goblin"); // STORE GOBLIN // ... } @Override public int onLoop() throws InterruptedException { switch (getState()) { //... case KILL: if (one_goblin_per_scan!= null && !myPlayer().isAnimating() && !(one_goblin_per_scan.isUnderAttack()) { (one_goblin_per_scan.interact("Attack"); sleep(random(800, 1000)); //... } I read what you placed down and implemented it into my code. Also, I fixed some errors. Here is my new code on the edited areas: private NPC one_goblin_per_scan; //... private State getState() { one_goblin_per_scan = npcs.closest("Goblin"); if (one_goblin_per_scan!= null && !myPlayer().isAnimating() && !(one_goblin_per_scan.isUnderAttack())) return State.KILL; GroundItem bones = groundItems.closest("Bones"); if (bones != null && !myPlayer().isUnderAttack()) return State.PICKUP; return State.WAIT; } case KILL: if (one_goblin_per_scan!= null && !myPlayer().isAnimating() && !(one_goblin_per_scan.isUnderAttack())) { one_goblin_per_scan.interact("Attack"); sleep(random(800, 1000)); } break; case WAIT: //Removed the timer in the WAIT case break; //Credits also to Botre What do you think? Thank you, Rutsy Edited March 3, 201510 yr by Rutsy
March 3, 201510 yr Author Yes looks good, I recommend you do the same for the bones cheers This is what I did for the bones: private GroundItem one_bone_per_scan; one_bone_per_scan = groundItems.closest("Bones"); if (one_bone_per_scan != null && !myPlayer().isUnderAttack()) return State.PICKUP; case PICKUP: Item bones = inventory.getItem("Bones"); if ((!inventory.isFull() && !myPlayer().isUnderAttack())) { one_bone_per_scan.interact("Take"); bones.interact("Bury"); sleep(random(300, 600)); } break; Is it better now? Thank you, Rutsy